Introducción

Este es un Notebook de R Markdown. Cuando se ejecuta código dentro del notebook, los resultados aparecen debajo del código.

Pueden ingresar a Canvas aquí.

El código se puede ejecutar de varias maneras:

  • Haciendo clic en el botón de Run,
  • Haciendo clic en el botón de Play en cada “chunk” (o pedazo de código),
  • Tecleando Ctrl+Shift+Enter dentro del “chunk” deseado.

Se pueden agregar nuevos “chunks” tecleando Ctrl+Alt+I o dando clic en Insert Chunk.

3 * 7
[1] 21
12 * 29
[1] 348

Cuando se escribe código en R no es necesario dejar espacios entre los comandos, pero sí es recomendable:

noeslomismoqueyoescribaasí a que yo escriba así.

R se puede utilizar como una calculadora. Las operaciones básicas se representan de la siguiente manera:

Operación Símbolo
Suma +
Resta -
Multiplicación *
División /
Potencia ^ ó **

Cuando simplemente realizamos alguna operación, esta se va a ejecutar en la consola, pero no se va a almacenar ningún resultado. Para poder almacenar datos, tablas, etc. es necesario definir variables. La convención en R para hacerlo es escribiendo una “flecha”: <- o -> (la más utilizada es la primera <-).

# esto es un comentario dentro del chunk de código
3 + 4
[1] 7
4 * 3
[1] 12
x <- 3 + 5 + 8 + 7 + 13 + 21 +
  14 + 
  4
x
[1] 75
3 ** 4
[1] 81
3 ^ 4
[1] 81

Para ver la versión renderizada del código, hay que hacer clic en el botón Preview.

NOTA: Aquí no es necesario escribir un “#” al inicio de la línea para crear texto (y no código).

Cuando se trabaja en RStudio, podemos crear proyectos (Rproj) que nos permiten organizar nuestro análisis de datos, junto con las tablas originales, los resultados, etc., de tal manera que es muy fácil de compartir y replicar por otras personas o en otros equipos.

Para dar claridad al código, se pueden agregar encabezados de distintos niveles. Esto se logra agregando un “#” Al inicio (para el primer orden de encabezado), “##” para el segundo, “###” para el tercero, etc.

Encabezado tipo 1

Hola

Encabezado tipo 2

Hola 2

Encabezado tipo 3

Hola 3

Otra ventaja de incluir secciones en su código es que eso te permite navegar de manera rápida entre ellas.

Otro atajo del teclado que es muy útil es (CTRL + Enter), que sirve para correr la(s) línea(s) de código seleccionada(s), o (CTRL + Shift + Enter) para correr todo el “chunk”. P. ej.:

print("¡Hola, mundo!")
[1] "¡Hola, mundo!"
print("¡Adiós, mundo!")
[1] "¡Adiós, mundo!"

Pueden agregar ecuaciones de \(\LaTeX\):

\[ \sum_{i=1}^n{3x_i + 4} \] También pueden escribir ecuaciones dentro de una línea de texto con \(\sum_{i=1}^n{3x_i + 4}\) solo un signo de pesos ($).

Pueden encontrar una guía muy completa sobre R Markdown aquí.

Carga de paqueterías

Una buena práctica es cargar todas las paqueterías necesarias al inicio del código, junto con variables que se especifiquen manualmente. Esto permite ser más claros sobre prerrequisitos o consideraciones que se realizan. Si la paquetería no está instalada, es necesario instalarla con install.packages("tidyverse"), p. ej.

install.packages("tidyverse")
library(tidyverse)
library(lubridate)
library(patchwork)
library(gapminder)
library(plotly)
library(gganimate)
library(quantmod)

Gráficas con ggplot2

Primero cargaremos los datos que utilizaremos de ejemplo para graficar.

data(mpg)
mpg

Después de analizar cada variable, vemos que las vars. categóricas (factores) están marcadas como “chr” (character o texto), por lo cual sería conveniente cambiar algunas de ellas a factores.

Si queremos cambiar el fabricante a factor y hwy (que está medida en “millas por galón” a “km por litro”), podemos usar mutate():

mpg <- mpg %>% # pipe operator
  mutate(manufacturer = as_factor(manufacturer),
         hwy = hwy * 1.609 / 3.785)
mpg

Si queremos aplicar la misma transformación a varias vars. podemos usar mutate_at() para escoger las variables, o mutate_if() para que, con base en una condición, R escoja las variables a modificar:

mpg <- mpg %>% 
  mutate_at(.vars = c("class",
                      "drv",
                      "cyl"), 
            .funs = as_factor) %>% 
  mutate(trans = fct_lump_min(trans, 20, 
                              other_level = "Otros"))
mpg

Teniendo nuestros datos ya limpios, podemos proceder a graficarlos y conocer varios tipos de gráficas que se pueden hacer con ggplot2.

Graficaremos la var. displ en el eje x y la variable hwy en el eje y. Haremos un diagrama de dispersión.

ggplot(data = mpg) + 
  geom_point(mapping = aes(y = hwy, x = displ))

Un gráfico de ggplot siempre comenzará con la función ggplot(), que genera un sistema de coordenadas, al que agregamos capas. En este caso, agregamos una capa de “puntos”, mapeando, a traves de aes() las variables x ^ y.

Modificar el color, forma y tamaño

Si se desea controlar el color, forma, tamaño, transparencia, etc. a través de alguna otra variable, se puede hacer incluyéndola dentro del aes() del ggplot().

Color

Ahora queremos cambiar el color de los puntos, de acuerdo a una tercera variable: la clase de auto (class).

Forma

De forma alternativa, pudimos haber cambiado la forma de los puntos, dependiendo la clase (en vez del color), con shape.

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy, 
                           shape = class))

Transparencia

O la transparencia de los mismos con alpha:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy, 
                           alpha = class))

Tamaño

O el tamaño con size:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy, 
                           size = class))

Disclaimer: Los gráficos anteriores son de carácter meramente ilustrativo. Como se aprecia en los warnings, algunas de esas configuraciones no son ideales para este tipo de variables.


Otras personalizaciones

Si, por otro lado, se quisiera cambiar alguno de esos atributos por default, sin que éstos dependan de alguna variable, se puede hacer si se especifican fuera del aes()

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy),
             color = "blue")

Cuidado, porque si se pone dentro del aes() no va a dar el resultado que buscamos:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = "blue")) +
  ggtitle("Definir el color fijo dentro del aes() produce errores")

También se pueden juntar varios de estos atributos al mismo tiempo, si eso se deseara:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy,
                           color = class,
                           shape = drv,
                           size = cyl),
             alpha = 0.7)

Se pueden asociar varias características a la misma variable:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy,
                           color = class,
                           shape = class,
                           size = class),
             alpha = 0.7)

Varias gráficas en una sola con patchwork

Los gráficos que recién creamos pueden ser almacenados en variables. La paquetería patchwork nos permite juntar dos o más gráficas de ggplot en una sola imagen. Retomemos algunas de las gráficas anteriores.

NOTA: El nombre se escoge arbitrariamente.

# Las gráficas a poner en una sola imagen
g1 <- ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))+
  ggtitle("La gráfica más básica")

g2 <- ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = class))+
  ggtitle("Color variable")

g3 <- ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), color = "blue")+
  ggtitle("Color fijo")

g4 <- ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy,
                           color = class,
                           shape = drv,
                           size = cyl),
             alpha = 0.7) + 
  ggtitle("Col, forma y tam var, alpha fija")

El acomodo se puede guardar en una variable también. Con patchwork es bastante intuitiva la manera de acomodar las gráficas.

  • + sirve para agregar gráficos en esa línea (también funciona utilizar |).

  • / sirve para crear una nueva fila.

fig1 <- g1 /
  (g2 + g3) /
  g4

fig1

Se pueden agregar títulos y subtítulos globales con plot_annotation(). También, se puede dejar espacios en blanco usando plot_spacer():

fig1 + 
  plot_annotation(title = "Gráficas con ggplot2",
                  subtitle = "Cambiando la estética de varias maneras")


(g1 + plot_spacer()) /
  (g4) /
  (g2 + g3) +
  plot_annotation(title = "Gráficas con ggplot2",
                  subtitle = "Otro acomodo distinto")


2 * 4 + 10
[1] 18

Uso de facetas

Otra opción para personalizar gráficas es utilizar facetas. Esto divide nuestro gráfico en varios subgráficos, de acuerdo a alguna variable especificada.

facet_wrap()

Para separar los subgráficos con base en una variable:

ggplot(data = mpg) + 
    geom_point(mapping = aes(x = displ, 
                             y = hwy,
                             color = class,
                             shape = drv),
               alpha = 0.7) + 
    ggtitle("Facetas por cilindraje") +
  facet_wrap(~ cyl)

facet_grid()

Las facetas se pueden poner en ambos ejes, usando dos variables:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, 
                           y = hwy,
                           color = class),
             alpha = 0.5) + 
  ggtitle("Facetas por tracción y cilindraje") +
  facet_grid(cyl ~ drv)

Gráficas de líneas

Otro tipo de gráfico muy utilizado es el de líneas. Usaremos otro conjunto de datos para esto.

data("economics")

Se puede acceder a la documentación de este dataset (y de cualquier función), a través de la función help():

help("economics")

Estos datos que hemos trabajado son de tipo tibble. Podemos observar lgunas diferencias entre un objeto tibble y un data.frame tradicional:

Tibble

Te muestra solo las primeras 10 filas, así como el tipo de datos de cada columna. También te da en resumen la dimensión de la tabla (filas x columnas).

economics
# A tibble: 574 x 6
#    date         pce    pop psavert uempmed unemploy
#    <date>     <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
#  1 1967-07-01  507. 198712    12.6     4.5     2944
#  2 1967-08-01  510. 198911    12.6     4.7     2945
#  3 1967-09-01  516. 199113    11.9     4.6     2958
#  4 1967-10-01  512. 199311    12.9     4.9     3143
#  5 1967-11-01  517. 199498    12.8     4.7     3066
#  6 1967-12-01  525. 199657    11.8     4.8     3018
#  7 1968-01-01  531. 199808    11.7     5.1     2878
#  8 1968-02-01  534. 199920    12.3     4.5     3001
#  9 1968-03-01  544. 200056    11.7     4.1     2877
# 10 1968-04-01  544  200208    12.3     4.6     2709
# ... with 564 more rows

Data.frame

as.data.frame(economics)
#           date    pce    pop psavert uempmed unemploy
# 1   1967-07-01  506.7 198712    12.6     4.5     2944
# 2   1967-08-01  509.8 198911    12.6     4.7     2945
# 3   1967-09-01  515.6 199113    11.9     4.6     2958
# 4   1967-10-01  512.2 199311    12.9     4.9     3143
# 5   1967-11-01  517.4 199498    12.8     4.7     3066
# 6   1967-12-01  525.1 199657    11.8     4.8     3018
# 7   1968-01-01  530.9 199808    11.7     5.1     2878
# 8   1968-02-01  533.6 199920    12.3     4.5     3001
# 9   1968-03-01  544.3 200056    11.7     4.1     2877
# 10  1968-04-01  544.0 200208    12.3     4.6     2709
# 11  1968-05-01  549.8 200361    12.0     4.4     2740
# 12  1968-06-01  556.3 200536    11.7     4.4     2938
# 13  1968-07-01  563.2 200706    10.7     4.5     2883
# 14  1968-08-01  567.0 200898    10.5     4.2     2768
# 15  1968-09-01  568.2 201095    10.6     4.6     2686
# 16  1968-10-01  571.6 201290    10.8     4.8     2689
# 17  1968-11-01  576.7 201466    10.6     4.4     2715
# 18  1968-12-01  576.5 201621    11.1     4.4     2685
# 19  1969-01-01  583.5 201760    10.3     4.4     2718
# 20  1969-02-01  588.7 201881     9.7     4.9     2692
# 21  1969-03-01  588.9 202023    10.2     4.0     2712
# 22  1969-04-01  593.9 202161     9.7     4.0     2758
# 23  1969-05-01  600.3 202331    10.1     4.2     2713
# 24  1969-06-01  600.9 202507    11.1     4.4     2816
# 25  1969-07-01  602.7 202677    11.8     4.4     2868
# 26  1969-08-01  609.9 202877    11.5     4.4     2856
# 27  1969-09-01  613.2 203090    11.6     4.7     3040
# 28  1969-10-01  618.5 203302    11.4     4.5     3049
# 29  1969-11-01  620.5 203500    11.6     4.8     2856
# 30  1969-12-01  622.8 203675    11.8     4.6     2884
# 31  1970-01-01  628.7 203849    11.8     4.6     3201
# 32  1970-02-01  634.0 204008    11.7     4.5     3453
# 33  1970-03-01  632.3 204156    12.4     4.6     3635
# 34  1970-04-01  636.0 204401    13.3     4.1     3797
# 35  1970-05-01  642.4 204607    12.4     4.7     3919
# 36  1970-06-01  646.3 204830    12.3     4.9     4071
# 37  1970-07-01  648.5 205052    13.5     5.1     4175
# 38  1970-08-01  652.9 205295    13.4     5.4     4256
# 39  1970-09-01  659.1 205540    12.9     5.2     4456
# 40  1970-10-01  658.3 205788    13.1     5.2     4591
# 41  1970-11-01  656.6 206024    13.6     5.6     4898
# 42  1970-12-01  665.6 206238    13.2     5.9     5076
# 43  1971-01-01  676.1 206466    13.3     6.2     4986
# 44  1971-02-01  679.4 206668    13.3     6.3     4903
# 45  1971-03-01  682.0 206855    13.5     6.4     4987
# 46  1971-04-01  688.8 207065    13.2     6.5     4959
# 47  1971-05-01  691.1 207260    13.6     6.7     4996
# 48  1971-06-01  699.8 207462    14.7     5.7     4949
# 49  1971-07-01  698.9 207661    13.8     6.2     5035
# 50  1971-08-01  704.9 207881    13.6     6.4     5134
# 51  1971-09-01  713.0 208114    13.3     5.8     5042
# 52  1971-10-01  715.8 208345    13.3     6.5     4954
# 53  1971-11-01  720.9 208555    13.1     6.4     5161
# 54  1971-12-01  728.4 208740    13.0     6.2     5154
# 55  1972-01-01  731.5 208917    12.5     6.2     5019
# 56  1972-02-01  736.2 209061    12.8     6.6     4928
# 57  1972-03-01  749.2 209212    11.8     6.6     5038
# 58  1972-04-01  752.5 209386    11.5     6.7     4959
# 59  1972-05-01  758.0 209545    11.7     6.6     4922
# 60  1972-06-01  761.6 209725    11.7     5.4     4923
# 61  1972-07-01  769.9 209896    11.7     6.1     4913
# 62  1972-08-01  776.3 210075    12.0     6.0     4939
# 63  1972-09-01  781.1 210278    12.2     5.6     4849
# 64  1972-10-01  794.9 210479    13.0     5.7     4875
# 65  1972-11-01  800.5 210656    13.6     5.7     4602
# 66  1972-12-01  806.1 210821    13.7     6.1     4543
# 67  1973-01-01  816.5 210985    12.4     5.7     4326
# 68  1973-02-01  825.8 211120    12.5     5.2     4452
# 69  1973-03-01  832.8 211254    12.7     5.5     4394
# 70  1973-04-01  835.7 211420    13.2     5.0     4459
# 71  1973-05-01  841.6 211577    13.2     4.9     4329
# 72  1973-06-01  844.3 211746    13.6     5.0     4363
# 73  1973-07-01  854.1 211909    13.2     5.2     4305
# 74  1973-08-01  853.3 212092    13.9     4.9     4305
# 75  1973-09-01  869.2 212289    13.1     5.4     4350
# 76  1973-10-01  868.2 212475    14.4     5.5     4144
# 77  1973-11-01  876.9 212634    14.4     5.1     4396
# 78  1973-12-01  876.6 212785    14.8     4.7     4489
# 79  1974-01-01  884.5 212932    14.3     5.0     4644
# 80  1974-02-01  889.7 213074    14.2     5.1     4731
# 81  1974-03-01  901.4 213211    13.4     4.8     4634
# 82  1974-04-01  910.8 213361    13.1     5.0     4618
# 83  1974-05-01  922.4 213513    12.8     4.6     4705
# 84  1974-06-01  928.0 213686    12.8     5.3     4927
# 85  1974-07-01  937.9 213854    12.8     5.7     5063
# 86  1974-08-01  954.8 214042    12.1     5.0     5022
# 87  1974-09-01  955.1 214246    12.9     5.3     5437
# 88  1974-10-01  959.2 214451    13.4     5.5     5523
# 89  1974-11-01  956.2 214625    13.8     5.2     6140
# 90  1974-12-01  961.8 214782    14.0     5.7     6636
# 91  1975-01-01  975.6 214931    13.2     6.3     7501
# 92  1975-02-01  989.4 215065    12.5     7.1     7520
# 93  1975-03-01  990.6 215198    12.7     7.2     7978
# 94  1975-04-01  995.0 215353    14.2     8.7     8210
# 95  1975-05-01 1018.9 215523    17.3     9.4     8433
# 96  1975-06-01 1026.8 215768    14.3     8.8     8220
# 97  1975-07-01 1039.8 215973    12.6     8.6     8127
# 98  1975-08-01 1047.0 216195    13.0     9.2     7928
# 99  1975-09-01 1054.8 216393    13.0     9.2     7923
# 100 1975-10-01 1060.9 216587    13.4     8.6     7897
# 101 1975-11-01 1075.8 216771    12.7     9.5     7794
# 102 1975-12-01 1092.1 216931    12.0     9.0     7744
# 103 1976-01-01 1107.1 217095    11.7     9.0     7534
# 104 1976-02-01 1107.7 217249    12.3     8.2     7326
# 105 1976-03-01 1114.9 217381    12.2     8.7     7230
# 106 1976-04-01 1125.4 217528    11.7     8.2     7330
# 107 1976-05-01 1122.7 217685    12.3     8.3     7053
# 108 1976-06-01 1140.5 217861    11.4     7.8     7322
# 109 1976-07-01 1149.6 218035    11.7     7.7     7490
# 110 1976-08-01 1158.0 218233    11.7     7.9     7518
# 111 1976-09-01 1168.8 218440    11.4     7.8     7380
# 112 1976-10-01 1176.8 218644    11.1     7.7     7430
# 113 1976-11-01 1189.0 218834    11.4     8.4     7620
# 114 1976-12-01 1211.5 219006    10.6     8.0     7545
# 115 1977-01-01 1215.0 219179    10.6     7.5     7280
# 116 1977-02-01 1231.3 219344     9.3     7.2     7443
# 117 1977-03-01 1238.3 219504    10.5     7.2     7307
# 118 1977-04-01 1247.3 219684    10.5     7.3     7059
# 119 1977-05-01 1257.1 219859    10.3     7.9     6911
# 120 1977-06-01 1263.6 220046    10.6     6.2     7134
# 121 1977-07-01 1280.5 220239    10.5     7.1     6829
# 122 1977-08-01 1285.7 220458    10.9     7.0     6925
# 123 1977-09-01 1294.5 220688    11.1     6.7     6751
# 124 1977-10-01 1311.4 220904    11.0     6.9     6763
# 125 1977-11-01 1327.0 221109    11.2     7.0     6815
# 126 1977-12-01 1336.0 221303    11.4     6.8     6386
# 127 1978-01-01 1329.5 221477    11.9     6.5     6489
# 128 1978-02-01 1355.1 221629    11.1     6.7     6318
# 129 1978-03-01 1377.5 221792    11.0     6.2     6337
# 130 1978-04-01 1396.4 221991    10.8     6.1     6180
# 131 1978-05-01 1412.0 222176    10.3     5.7     6127
# 132 1978-06-01 1425.8 222379    10.0     6.0     6028
# 133 1978-07-01 1426.8 222585    10.9     5.8     6309
# 134 1978-08-01 1447.0 222805    10.5     5.8     6080
# 135 1978-09-01 1452.9 223053    10.6     5.6     6125
# 136 1978-10-01 1466.9 223271    10.7     5.9     5947
# 137 1978-11-01 1480.6 223477    10.5     5.5     6077
# 138 1978-12-01 1496.5 223670    10.4     5.6     6228
# 139 1979-01-01 1502.4 223865    11.1     5.9     6109
# 140 1979-02-01 1517.8 224053    11.1     5.9     6173
# 141 1979-03-01 1531.2 224235    11.2     5.9     6109
# 142 1979-04-01 1538.4 224438    11.0     5.4     6069
# 143 1979-05-01 1558.8 224632    10.3     5.6     5840
# 144 1979-06-01 1575.7 224843     9.9     5.6     5959
# 145 1979-07-01 1586.1 225055    10.6     5.9     5996
# 146 1979-08-01 1615.6 225295     9.7     4.8     6320
# 147 1979-09-01 1633.9 225547     9.4     5.5     6190
# 148 1979-10-01 1641.6 225801     9.7     5.5     6296
# 149 1979-11-01 1657.3 226027     9.7     5.3     6238
# 150 1979-12-01 1666.3 226243    10.1     5.7     6325
# 151 1980-01-01 1697.3 226451     9.9     5.3     6683
# 152 1980-02-01 1701.4 226656    10.1     5.8     6702
# 153 1980-03-01 1708.2 226849    10.2     6.0     6729
# 154 1980-04-01 1695.2 227061    11.3     5.8     7358
# 155 1980-05-01 1700.1 227251    11.4     5.7     7984
# 156 1980-06-01 1718.8 227522    11.2     6.4     8098
# 157 1980-07-01 1747.1 227726    11.3     7.0     8363
# 158 1980-08-01 1763.8 227953    11.3     7.5     8281
# 159 1980-09-01 1780.5 228186    11.7     7.7     8021
# 160 1980-10-01 1817.1 228417    11.3     7.5     8088
# 161 1980-11-01 1826.8 228612    11.6     7.7     8023
# 162 1980-12-01 1851.7 228779    11.4     7.5     7718
# 163 1981-01-01 1870.0 228937    10.9     7.4     8071
# 164 1981-02-01 1884.2 229071    10.8     7.1     8051
# 165 1981-03-01 1902.9 229224    10.8     7.1     7982
# 166 1981-04-01 1904.4 229403    10.9     7.4     7869
#  [ reached 'max' / getOption("max.print") -- omitted 408 rows ]


Grafiquemos el desempleo a lo largo del tiempo.

ggplot(economics,
       aes(x = date, y = unemploy)) + 
  geom_line()

Filtrando los datos y añadiendo dos capas de gráficos (puntos y líneas):

ggplot(economics %>% filter(year(date)>=2006),
       aes(x = date, y = unemploy)) + 
  geom_line(color = "red") + 
  geom_point(size = 1, color ="forestgreen")

Sería exactamente el mismo resultado si definimos el aes() dentro de cada uno de los geoms:

ggplot(economics %>% filter(year(date)>=2006)) + 
  geom_line(aes(x = date, y = unemploy), color = "red") + 
  geom_point(aes(x = date, y = unemploy), size = 1, color ="forestgreen")

Se pueden crear sus propias tibbles directamente en R con la función tibble():

tibble(fecha = c("31 aug 20","1-sep-20","02/9/2020"),
       dolar = c(24,24.3,25),
       `dia caluroso` = c(1, 0, 1)) %>%
  mutate(fecha = dmy(fecha), 
         `dia caluroso` = as.integer(`dia caluroso`),
         `dia caluroso 2` = as.logical(`dia caluroso`))

# Esto marcaría un error:
# 2 <- 4
# Se puede hacer esto, pero NO es recomendable
`2` <- 4
`2`
[1] 4

Transformación de datos con dplyr

Utilizaremos los datos de gapminder para revisar varios ejemplos. Explorando la tabla, vemos que contiene 1,704 filas con 6 columnas:

  • País country
  • Continente continent
  • Año year
  • Esperanza de vida (en años) lifeExp
  • Población pop
  • PIB per cápita (en USD, ajustados por la inflación) gdpPercap
data(gapminder)
gapminder

gapminder %>% 
  distinct(country) %>% 
  nrow()
[1] 142
# levels(gapminder$country)

Si quisiéramos filtrar la tabla para mantener sólo los países asiáticos, lo podríamos lograr con el verbo filter(). Opcionalmente, podríamos validar con distinct() si nuestro filtro logró el objetivo:

# Para quedarnos solo con países asiáticos
gapminder %>% 
  filter(continent == "Asia")
# Validación
gapminder %>% 
  filter(continent == "Asia") %>% 
  distinct(continent)

gapminder %>% 
  distinct(continent)

Vemos que las filas de la tabla se redujeron (a 396) y que, efectivamente, logramos el objetivo de mantener puros países de Asia.

Podemos ordenar una tabla con respecto a una de sus variables con arrange(). Por defáult, el orden será ascendente. Si se desea en orden descendente, agregamos desc(). Probemos mostrando a los países que tienen la mayor población en el año 2007.

gapminder %>% 
  filter(year == 2007) %>% 
  arrange(desc(pop))

Para quedarnos con los años a partir de 1997.

Pero si quisiéramos quedarnos con los años 1952, 1972, 2002, 2007, ¿cómo lo podríamos hacer?

Lo podríamos lograr con la función %in%:

gapminder %>% 
  filter(year %in% c(1952, 1972, 2002, 2007),
         country == "Mexico")

Ahora, si deseáramos obtener una subgráfica de líneas de cuantro países asiáticos (Nepal, Irak, Cambodia y China), lo podríamos hacer de la siguiente forma:

gapminder %>% 
  filter(country %in% c("Nepal", "Iraq", "Cambodia","China")) %>% 
  ggplot(aes(x = year, y = lifeExp)) +
  geom_line() + 
  facet_wrap(~ country) +
  ggtitle("Separación de los países por facetas")

Otra alternativa sería mostrar una sola gráfica y definir el color de línea por país. Aquí se ejemplifica también cómo cambiar el nombre de los ejes, la posición de la leyenda, entre otros.

gapminder %>% 
  filter(country %in% c("Indonesia","India","Oman", "Taiwan")) %>% 
  ggplot(aes(x = year, y = lifeExp, color = country)) +
  geom_line() +
  ylab("Esperanza de vida (años)") + xlab("") +
  ggtitle("Cambio de la esperanza de vida para algunos paises asiáticos") +
  labs(color = "País") + theme(legend.position = "bottom")

Otra manera de especificar los nombres de ejes y el título es directamente dentro de labs():

gapminder %>% 
  filter(country %in% c("Indonesia","India","Oman", "Taiwan")) %>% 
  ggplot(aes(x = year, y = lifeExp, color = country)) +
  geom_line() +
  labs(x = "", 
       y = "Esperanza de vida (años)", 
       title = "Cambio de la esperanza de vida en algunos países asiáticos", 
       color = "") + 
  theme(legend.position = "top")

Se podrían hacer más configuraciones:

gapminder %>% 
  filter(country %in% c("Indonesia","India","Oman", "Taiwan")) %>% 
  ggplot(aes(x = year, y = lifeExp, color = country, linetype = country)) +
  geom_line() +
  ylab("Esperanza de vida (años)") + xlab("") +
  ggtitle("Cambio de la esperanza de vida para algunos paises asiáticos") +
  labs(color = "", linetype ="") + 
  theme(legend.position = "bottom")

Podemos analizar la relación entre la esperanza de vida y el PIB per cápita, ya que se dice que existe una relación directa entre ambas.

Haremos el análisis para el año 2007:

gapminder %>% 
  filter(year == 2007) %>%
  ggplot(aes(x = gdpPercap, y = lifeExp, color = continent,
             size = pop)) +
  geom_point() + 
  scale_x_log10() +
  ylab("Esperanza de vida (años)") +
  xlab("PIB per cápita (USD con ajuste inflacionario, escala log10)") + 
  labs(color ="", size="")

gapminder %>% 
  filter(country %in% c("Canada", "Mexico", "Brazil"),
         year == 2007) %>% 
  select(year, country, pop)

Pero, ¿qué pasa si queremos observar el cambio de estos factores a lo largo del tiempo? Claro, podríamos crear muchas gráficas distintas, cambiando el argumento filter(year == "cada uno de los años"). Pero esto, aparte de que sería laborioso, no sería práctico para analizarlo.

Gráficas interactivas

plotly

Lo que podemos hacer es crear una gráfica interactiva, apoyados de la paquetería plotly. Los cambios que tenemos que hacer en este caso en particular son muy sencillos. Pueden consultar este libro electrónico para más detalles.

  • Haber instalado y cargado plotly
  • Agregar aes(frame = year) a la estética de la gráfica.
  • Guardar el gráfico en una variable (el nombre es indiferente), y posteriormente ejecutar la función ggplotly() con la variable que contiene al gráfico.

NOTA: Casi cualquier gráfico hecho con ggplot2 se puede convertir en uno interactivo con la función ggplotly().

int_plot1 <- gapminder %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp, color = continent,
             size = pop, label = country)) +
  geom_point(aes(frame = year)) + 
  scale_x_log10() + 
  ylab("Esperanza de vida (años)") +
  xlab("PIB per cápita (USD con ajuste inflacionario)") + 
  labs(color ="", size="")
Ignoring unknown aesthetics: frame
ggplotly(int_plot1)
int_plot2 <- gapminder %>% 
  ggplot(aes(x = gdpPercap, y = lifeExp, color = country,
             size = pop, label = country)) +
  geom_point(aes(frame = year)) + 
  scale_x_log10() + 
  facet_wrap(~ continent) +
  ylab("Esperanza de vida (años)") +
  xlab("PIB per cápita (USD con ajuste inflacionario)") + 
  # labs(color ="", size="")
  theme(legend.position = "none")
Ignoring unknown aesthetics: frame
  
ggplotly(int_plot2)
`group_by_()` is deprecated as of dplyr 0.7.0.
Please use `group_by()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

Otro tipo de gráfico que puede proporcionarnos mucha información es un diagrama de caja y bigotes. Aquí, la interpretación es algo así:

  • Los bigotes muestran los valores mínimo y máximo (sin considerar outliers),
  • el inicio de la caja representa el primer cuartil (25% de los datos),
  • La línea interna de la caja es la mediana (el 50% de los datos),
  • el final de la caja muestra el tercer cuartil (75% de los datos) y,
  • en caso de que la gráfica muestre puntos fuera de la caja, se considerarían como outliers.
gap_box <- gapminder %>%
  filter(year == 2007) %>% 
  ggplot(aes(x = continent, y = lifeExp)) +
  geom_boxplot()

ggplotly(gap_box)

Definiendo una función especial, se pueden crear gráficas acumulativas de líneas también:

invisible(getSymbols("AAPL",src='yahoo'))
㤼㸱getSymbols㤼㸲 currently uses auto.assign=TRUE by default, but will
use auto.assign=FALSE in 0.5-0. You will still be able to use
㤼㸱loadSymbols㤼㸲 to automatically load data. getOption("getSymbols.env")
and getOption("getSymbols.auto.assign") will still be checked for
alternate defaults.

This message is shown once per session and may be disabled by setting 
options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.

AAPL download failed; trying again.
df <- data.frame(Date=zoo::index(AAPL),coredata(AAPL))
df <- tail(df, 30)
df$ID <- seq.int(nrow(df))

accumulate_by <- function(dat, var) {
  var <- lazyeval::f_eval(var, dat)
  lvls <- plotly:::getLevels(var)
  dats <- lapply(seq_along(lvls), function(x) {
    cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
  })
  dplyr::bind_rows(dats)
}

df <- df %>%
  accumulate_by(~ID)

p <- ggplot(df,aes(ID, AAPL.Close, frame = frame)) +
  geom_line()

fig <- ggplotly(p) %>%
  layout(
    title = "AAPL: Last 30 days",
    yaxis = list(
      title = "Close",
      zeroline = F,
      tickprefix = "$"
    ),
    xaxis = list(
      title = "Day",
      zeroline = F, 
      showgrid = F
    )
  ) %>% 
  animation_opts(
    frame = 100, 
    transition = 0, 
    redraw = FALSE
  ) %>%
  animation_slider(
    currentvalue = list(
      prefix = "Day "
    )
  )

fig
Warning in for (i in seq_len(n)) { :
  closing unused connection 3 (https://query2.finance.yahoo.com/v7/finance/download/AAPL?period1=1167609600&period2=1598486400&interval=1d&events=history&crumb=qg6NVAeFT8v)

gganimate

Esto no funciona igual para un gráfico de líneas. Existe otra paquetería que nos permite hacer cosas similares: gganimate. Esta página contiene un breve tutorial de varias opciones.

NOTA: *Se requiere instalar las paqueterías png y gifski adicionales a gganimate.

p1 <- gapminder %>% 
  filter(country %in% c("Mexico", "United States", "Chile")) %>%
  ggplot(aes(x = year, y = lifeExp,
             color = country)) + 
  geom_line() +
  theme(legend.position = "top") +
  labs(x = "Año", y = "Esperanza de vida (años)", 
       title = "Evolución de la esperanza de vida en el tiempo")

p1 + transition_reveal(year)

anim_save(filename = "figs/LifeExp_gganim.gif")

(figs/LifeExp_gganim.gif)

p <- ggplot(
  airquality,
  aes(Day, Temp, group = Month, color = factor(Month))
  ) +
  geom_line() +
  scale_color_viridis_d() +
  labs(x = "Day of Month", y = "Temperature") +
  theme(legend.position = "top")

p + transition_reveal(Day)

anim_save(filename = "figs/airquality.gif")

(figs/airquality.gif)

LS0tDQp0aXRsZTogIkludHJvZHVjY2nDs24gYSBSIg0Kc3VidGl0bGU6ICJBcHJlbmRpZW5kbyBhIHVzYXIgUiINCmF1dGhvcjogIlBhYmxvIEJlbmF2aWRlcyBIZXJyZXJhIg0KZGF0ZTogMjAyMC0wNS0yNw0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICB0aGVtZTogc3BhY2VsYWINCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KIyBJbnRyb2R1Y2Npw7NuDQoNCkVzdGUgZXMgdW4gTm90ZWJvb2sgZGUgW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pLiBDdWFuZG8gc2UgZWplY3V0YSBjw7NkaWdvIGRlbnRybyBkZWwgbm90ZWJvb2ssIGxvcyByZXN1bHRhZG9zIGFwYXJlY2VuIGRlYmFqbyBkZWwgY8OzZGlnby4gDQoNClB1ZWRlbiBpbmdyZXNhciBhICoqQ2FudmFzKiogW2FxdcOtXShodHRwczovL2l0ZXNvLmluc3RydWN0dXJlLmNvbSkuDQoNCkVsIGPDs2RpZ28gc2UgcHVlZGUgZWplY3V0YXIgZGUgdmFyaWFzIG1hbmVyYXM6DQoNCiogSGFjaWVuZG8gY2xpYyBlbiBlbCBib3TDs24gZGUgKlJ1biosDQoqIEhhY2llbmRvIGNsaWMgZW4gZWwgYm90w7NuIGRlICpQbGF5KiBlbiBjYWRhICJjaHVuayIgKG8gcGVkYXpvIGRlIGPDs2RpZ28pLA0KKiBUZWNsZWFuZG8gKkN0cmwrU2hpZnQrRW50ZXIqIGRlbnRybyBkZWwgImNodW5rIiBkZXNlYWRvLiANCg0KU2UgcHVlZGVuIGFncmVnYXIgbnVldm9zICJjaHVua3MiIHRlY2xlYW5kbyAqQ3RybCtBbHQrSSogbyBkYW5kbyBjbGljIGVuICpJbnNlcnQgQ2h1bmsqLg0KDQpgYGB7cn0NCjMgKiA3DQoxMiAqIDI5DQpgYGANCg0KKioqDQoNCkN1YW5kbyBzZSBlc2NyaWJlIGPDs2RpZ28gZW4gKipSKiogbm8gZXMgbmVjZXNhcmlvIGRlamFyIGVzcGFjaW9zIGVudHJlIGxvcyBjb21hbmRvcywgcGVybyBzw60gZXMgcmVjb21lbmRhYmxlOg0KDQo+IG5vZXNsb21pc21vcXVleW9lc2NyaWJhYXPDrSBhIHF1ZSB5byBlc2NyaWJhIGFzw60uDQoNCioqUioqIHNlIHB1ZWRlIHV0aWxpemFyIGNvbW8gdW5hIGNhbGN1bGFkb3JhLiBMYXMgb3BlcmFjaW9uZXMgYsOhc2ljYXMgc2UgcmVwcmVzZW50YW4gZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KfE9wZXJhY2nDs24gICAgICB8IFPDrW1ib2xvIHwNCnw6LS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS06fA0KfCAgICBTdW1hICAgICAgIHwgICAgKyAgICB8DQp8ICAgIFJlc3RhICAgICAgfCAgICAtICAgIHwNCnxNdWx0aXBsaWNhY2nDs24gfCAgICAqICAgIHwNCnwgIERpdmlzacOzbiAgICAgfCAgICAvICAgIHwNCnwgUG90ZW5jaWEgICAgICB8ICBeIMOzICoqIHwNCg0KQ3VhbmRvIHNpbXBsZW1lbnRlIHJlYWxpemFtb3MgYWxndW5hIG9wZXJhY2nDs24sIGVzdGEgc2UgdmEgYSBlamVjdXRhciBlbiBsYSBjb25zb2xhLCBwZXJvIG5vIHNlIHZhIGEgYWxtYWNlbmFyIG5pbmfDum4gcmVzdWx0YWRvLiBQYXJhIHBvZGVyIGFsbWFjZW5hciBkYXRvcywgdGFibGFzLCBldGMuIGVzIG5lY2VzYXJpbyBkZWZpbmlyICoqdmFyaWFibGVzKiouIExhIGNvbnZlbmNpw7NuIGVuICoqUioqIHBhcmEgaGFjZXJsbyBlcyBlc2NyaWJpZW5kbyB1bmEgKiJmbGVjaGEiKjogYDwtYCBvIGAtPmAgKGxhIG3DoXMgdXRpbGl6YWRhIGVzIGxhIHByaW1lcmEgYDwtYCkuDQoNCg0KDQpgYGB7ciBwcnVlYmF9DQojIGVzdG8gZXMgdW4gY29tZW50YXJpbyBkZW50cm8gZGVsIGNodW5rIGRlIGPDs2RpZ28NCjMgKyA0DQo0ICogMw0KeCA8LSAzICsgNSArIDggKyA3ICsgMTMgKyAyMSArDQogIDE0ICsgDQogIDQNCngNCg0KMyAqKiA0DQozIF4gNA0KYGBgDQoNClBhcmEgdmVyIGxhIHZlcnNpw7NuIHJlbmRlcml6YWRhIGRlbCBjw7NkaWdvLCBoYXkgcXVlIGhhY2VyIGNsaWMgZW4gZWwgYm90w7NuICpQcmV2aWV3Ki4NCg0KKipOT1RBOioqICpBcXXDrSBubyBlcyBuZWNlc2FyaW8gZXNjcmliaXIgdW4gIiMiIGFsIGluaWNpbyBkZSBsYSBsw61uZWEgcGFyYSBjcmVhciB0ZXh0byAoeSBubyBjw7NkaWdvKS4qDQoNCkN1YW5kbyBzZSB0cmFiYWphIGVuIFJTdHVkaW8sIHBvZGVtb3MgY3JlYXIgcHJveWVjdG9zIChScHJvaikgcXVlIG5vcyBwZXJtaXRlbiBvcmdhbml6YXIgbnVlc3RybyBhbsOhbGlzaXMgZGUgZGF0b3MsIGp1bnRvIGNvbiBsYXMgdGFibGFzIG9yaWdpbmFsZXMsIGxvcyByZXN1bHRhZG9zLCBldGMuLCBkZSB0YWwgbWFuZXJhIHF1ZSBlcyBtdXkgZsOhY2lsIGRlIGNvbXBhcnRpciB5IHJlcGxpY2FyIHBvciBvdHJhcw0KcGVyc29uYXMgbyBlbiBvdHJvcyBlcXVpcG9zLg0KDQoNClBhcmEgZGFyIGNsYXJpZGFkIGFsIGPDs2RpZ28sIHNlIHB1ZWRlbiBhZ3JlZ2FyIGVuY2FiZXphZG9zIGRlIGRpc3RpbnRvcyBuaXZlbGVzLiBFc3RvIHNlIGxvZ3JhIGFncmVnYW5kbyB1biAiIyIgQWwgaW5pY2lvIChwYXJhIGVsIHByaW1lciBvcmRlbiBkZSBlbmNhYmV6YWRvKSwgIiMjIiBwYXJhIGVsIHNlZ3VuZG8sICIjIyMiIHBhcmEgZWwgdGVyY2VybywgZXRjLg0KDQojIEVuY2FiZXphZG8gdGlwbyAxDQpIb2xhDQoNCiMjIEVuY2FiZXphZG8gdGlwbyAyDQoNCkhvbGEgMg0KDQojIyMgRW5jYWJlemFkbyB0aXBvIDMNCg0KSG9sYSAzDQoNCk90cmEgdmVudGFqYSBkZSBpbmNsdWlyIHNlY2Npb25lcyBlbiBzdSBjw7NkaWdvIGVzIHF1ZSBlc28gdGUgcGVybWl0ZSBuYXZlZ2FyIGRlIG1hbmVyYSByw6FwaWRhIGVudHJlIGVsbGFzLg0KDQpPdHJvIGF0YWpvIGRlbCB0ZWNsYWRvIHF1ZSBlcyBtdXkgw7p0aWwgZXMgKCpDVFJMICsgRW50ZXIqKSwgcXVlIHNpcnZlIHBhcmEgY29ycmVyIGxhKHMpIGzDrW5lYShzKSBkZSBjw7NkaWdvIHNlbGVjY2lvbmFkYShzKSwgbyAoKkNUUkwgKyBTaGlmdCArIEVudGVyKikgcGFyYQ0KY29ycmVyIHRvZG8gZWwgImNodW5rIi4gUC4gZWouOg0KDQpgYGB7ciBoZWxsby13b3JsZH0NCnByaW50KCLCoUhvbGEsIG11bmRvISIpDQpwcmludCgiwqFBZGnDs3MsIG11bmRvISIpDQpgYGANCg0KUHVlZGVuIGFncmVnYXIgZWN1YWNpb25lcyBkZSAkXExhVGVYJDoNCg0KJCQNClxzdW1fe2k9MX1ebnszeF9pICsgNH0NCiQkDQpUYW1iacOpbiBwdWVkZW4gZXNjcmliaXIgZWN1YWNpb25lcyBkZW50cm8gZGUgdW5hIGzDrW5lYSBkZSB0ZXh0byBjb24gJFxzdW1fe2k9MX1ebnszeF9pICsgNH0kIHNvbG8gdW4gc2lnbm8gZGUgcGVzb3MgKCQpLg0KDQoqKlB1ZWRlbiBlbmNvbnRyYXIgdW5hIGd1w61hIG11eSBjb21wbGV0YSBzb2JyZSBSIE1hcmtkb3duIFthcXXDrV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykuKioNCg0KIyMgQ2FyZ2EgZGUgcGFxdWV0ZXLDrWFzDQoNClVuYSBidWVuYSBwcsOhY3RpY2EgZXMgY2FyZ2FyIHRvZGFzIGxhcyBwYXF1ZXRlcsOtYXMgbmVjZXNhcmlhcyAgYWwgaW5pY2lvIGRlbCBjw7NkaWdvLCBqdW50byBjb24gdmFyaWFibGVzIHF1ZSBzZSBlc3BlY2lmaXF1ZW4gbWFudWFsbWVudGUuIEVzdG8gcGVybWl0ZSBzZXIgbcOhcyBjbGFyb3Mgc29icmUgcHJlcnJlcXVpc2l0b3MgbyBjb25zaWRlcmFjaW9uZXMgcXVlIHNlIHJlYWxpemFuLiBTaSBsYSBwYXF1ZXRlcsOtYSBubyBlc3TDoSBpbnN0YWxhZGEsIGVzIG5lY2VzYXJpbyBpbnN0YWxhcmxhIGNvbiBgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIilgLCBwLiBlai4NCg0KYGBge30NCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpgYGANCg0KDQpgYGB7ciBwa2dzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShnYXBtaW5kZXIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KbGlicmFyeShxdWFudG1vZCkNCmBgYA0KDQojIEdyw6FmaWNhcyBjb24gYGdncGxvdDJgDQoNClByaW1lcm8gY2FyZ2FyZW1vcyBsb3MgZGF0b3MgcXVlIHV0aWxpemFyZW1vcyBkZSBlamVtcGxvIHBhcmEgZ3JhZmljYXIuDQoNCmBgYHtyIGRhdG9zMX0NCmRhdGEobXBnKQ0KbXBnDQpgYGANCg0KRGVzcHXDqXMgZGUgYW5hbGl6YXIgY2FkYSB2YXJpYWJsZSwgdmVtb3MgcXVlIGxhcyB2YXJzLiBjYXRlZ8OzcmljYXMgKGZhY3RvcmVzKSBlc3TDoW4gbWFyY2FkYXMgY29tbyAiY2hyIiAoY2hhcmFjdGVyIG8gdGV4dG8pLCBwb3IgbG8gY3VhbCBzZXLDrWEgY29udmVuaWVudGUgY2FtYmlhciBhbGd1bmFzIGRlIGVsbGFzIGEgZmFjdG9yZXMuDQoNClNpIHF1ZXJlbW9zIGNhbWJpYXIgZWwgZmFicmljYW50ZSBhIGZhY3RvciB5IGh3eSAocXVlIGVzdMOhIG1lZGlkYSBlbiAibWlsbGFzIHBvciBnYWzDs24iIGEgImttIHBvciBsaXRybyIpLCBwb2RlbW9zIHVzYXIgYG11dGF0ZSgpYDoNCg0KYGBge3IgZGF0b3MxLW11dGF0ZX0NCm1wZyA8LSBtcGcgJT4lICMgcGlwZSBvcGVyYXRvcg0KICBtdXRhdGUobWFudWZhY3R1cmVyID0gYXNfZmFjdG9yKG1hbnVmYWN0dXJlciksDQogICAgICAgICBod3kgPSBod3kgKiAxLjYwOSAvIDMuNzg1KQ0KbXBnDQpgYGANCg0KU2kgcXVlcmVtb3MgYXBsaWNhciBsYSBtaXNtYSB0cmFuc2Zvcm1hY2nDs24gYSB2YXJpYXMgdmFycy4gcG9kZW1vcyB1c2FyIGBtdXRhdGVfYXQoKWAgcGFyYSBlc2NvZ2VyIGxhcyB2YXJpYWJsZXMsIG8gYG11dGF0ZV9pZigpYCBwYXJhIHF1ZSwgY29uIGJhc2UgZW4gdW5hIGNvbmRpY2nDs24sIFIgZXNjb2phIGxhcyB2YXJpYWJsZXMgYSBtb2RpZmljYXI6DQoNCmBgYHtyIGRhdG9zMS1tdXRhdGUyfQ0KbXBnIDwtIG1wZyAlPiUgDQogIG11dGF0ZV9hdCgudmFycyA9IGMoImNsYXNzIiwNCiAgICAgICAgICAgICAgICAgICAgICAiZHJ2IiwNCiAgICAgICAgICAgICAgICAgICAgICAiY3lsIiksIA0KICAgICAgICAgICAgLmZ1bnMgPSBhc19mYWN0b3IpICU+JSANCiAgbXV0YXRlKHRyYW5zID0gZmN0X2x1bXBfbWluKHRyYW5zLCAyMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdGhlcl9sZXZlbCA9ICJPdHJvcyIpKQ0KbXBnDQpgYGANCg0KVGVuaWVuZG8gbnVlc3Ryb3MgZGF0b3MgeWEgbGltcGlvcywgcG9kZW1vcyBwcm9jZWRlciBhIGdyYWZpY2FybG9zIHkgY29ub2NlciB2YXJpb3MgdGlwb3MgZGUgZ3LDoWZpY2FzIHF1ZSBzZSBwdWVkZW4gaGFjZXIgY29uIGBnZ3Bsb3QyLmANCg0KR3JhZmljYXJlbW9zIGxhIHZhci4gZGlzcGwgZW4gZWwgZWplIHggeSBsYSB2YXJpYWJsZSBod3kgZW4gZWwgZWplIHkuIEhhcmVtb3MgdW4gZGlhZ3JhbWEgZGUgZGlzcGVyc2nDs24uDQoNCmBgYHtyIGdlb21fcG9pbnR9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHkgPSBod3ksIHggPSBkaXNwbCkpDQpgYGANCg0KDQpVbiBncsOhZmljbyBkZSBnZ3Bsb3Qgc2llbXByZSBjb21lbnphcsOhIGNvbiBsYSBmdW5jacOzbiBgZ2dwbG90KClgLCBxdWUgZ2VuZXJhIHVuIHNpc3RlbWEgZGUgY29vcmRlbmFkYXMsIGFsIHF1ZSBhZ3JlZ2Ftb3MgY2FwYXMuIEVuIGVzdGUgY2FzbywgYWdyZWdhbW9zIHVuYSBjYXBhIGRlICJwdW50b3MiLCBtYXBlYW5kbywgYSB0cmF2ZXMgZGUgYGFlcygpYCBsYXMgdmFyaWFibGVzICp4KiBeICp5Ki4NCg0KDQojIyBNb2RpZmljYXIgZWwgY29sb3IsIGZvcm1hIHkgdGFtYcOxbyB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNClNpIHNlIGRlc2VhIGNvbnRyb2xhciBlbCBjb2xvciwgZm9ybWEsIHRhbWHDsW8sIHRyYW5zcGFyZW5jaWEsIGV0Yy4gYSB0cmF2w6lzIGRlIGFsZ3VuYSBvdHJhIHZhcmlhYmxlLCBzZSBwdWVkZSBoYWNlciBpbmNsdXnDqW5kb2xhIGRlbnRybyBkZWwgYGFlcygpYCBkZWwgYGdncGxvdCgpYC4NCg0KIyMjIENvbG9yDQoNCkFob3JhIHF1ZXJlbW9zIGNhbWJpYXIgZWwgYGNvbG9yYCBkZSBsb3MgcHVudG9zLCBkZSBhY3VlcmRvIGEgdW5hIHRlcmNlcmEgdmFyaWFibGU6IGxhIGNsYXNlIGRlIGF1dG8gKGBjbGFzc2ApLg0KDQpgYGB7ciBnZW9tX3BvaW50LWNvbG9yLCBlY2hvPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjbGFzcykNCiAgICAgICAgICAgICApDQpgYGANCg0KIyMjIEZvcm1hDQoNCkRlIGZvcm1hIGFsdGVybmF0aXZhLCBwdWRpbW9zIGhhYmVyIGNhbWJpYWRvIGxhIGZvcm1hIGRlIGxvcyBwdW50b3MsIGRlcGVuZGllbmRvIGxhIGNsYXNlIChlbiB2ZXogZGVsIGNvbG9yKSwgY29uIGBzaGFwZWAuDQoNCmBgYHtyIGdlb21fcG9pbnQtc2hhcGV9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gY2xhc3MpKQ0KYGBgDQoNCiMjIyBUcmFuc3BhcmVuY2lhDQpPIGxhIHRyYW5zcGFyZW5jaWEgZGUgbG9zIG1pc21vcyBjb24gYGFscGhhYDoNCg0KYGBge3IgZ2VvbV9wb2ludC1hbHBoYX0NCmdncGxvdChkYXRhID0gbXBnKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBod3ksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSBjbGFzcykpDQpgYGANCg0KIyMjIFRhbWHDsW8NCg0KTyBlbCB0YW1hw7FvIGNvbiBgc2l6ZWA6DQoNCmBgYHtyIGdlb21fcG9pbnQtc2l6ZX0NCmdncGxvdChkYXRhID0gbXBnKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBod3ksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGNsYXNzKSkNCmBgYA0KDQojIyB7LX0NCioqRGlzY2xhaW1lcjoqKiAqTG9zIGdyw6FmaWNvcyBhbnRlcmlvcmVzIHNvbiBkZSBjYXLDoWN0ZXIgbWVyYW1lbnRlIGlsdXN0cmF0aXZvLiBDb21vIHNlIGFwcmVjaWEgZW4gbG9zIHdhcm5pbmdzLCBhbGd1bmFzIGRlIGVzYXMgY29uZmlndXJhY2lvbmVzIG5vIHNvbiBpZGVhbGVzIHBhcmEgZXN0ZSB0aXBvIGRlIHZhcmlhYmxlcy4qDQoNCioqKg0KIyMgT3RyYXMgcGVyc29uYWxpemFjaW9uZXMNCg0KU2ksIHBvciBvdHJvIGxhZG8sIHNlIHF1aXNpZXJhIGNhbWJpYXIgYWxndW5vIGRlIGVzb3MgYXRyaWJ1dG9zIHBvciBkZWZhdWx0LCBzaW4gcXVlIMOpc3RvcyBkZXBlbmRhbiBkZSBhbGd1bmEgdmFyaWFibGUsIHNlIHB1ZWRlIGhhY2VyIHNpIHNlIGVzcGVjaWZpY2FuIGZ1ZXJhIGRlbCBgYWVzKClgDQoNCmBgYHtyIGdlb21fcG9pbnQtZml4ZWQgY29sb3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5KSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibHVlIikNCmBgYA0KDQpDdWlkYWRvLCBwb3JxdWUgc2kgc2UgcG9uZSBkZW50cm8gZGVsIGFlcygpIG5vIHZhIGEgZGFyIGVsIHJlc3VsdGFkbyBxdWUgYnVzY2Ftb3M6DQoNCmBgYHtyIGdlb21fcG9pbnQtY29sb3Itd3JvbmcsIG1lc3NhZ2U9RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSAiYmx1ZSIpKSArDQogIGdndGl0bGUoIkRlZmluaXIgZWwgY29sb3IgZmlqbyBkZW50cm8gZGVsIGFlcygpIHByb2R1Y2UgZXJyb3JlcyIpDQpgYGANCg0KVGFtYmnDqW4gc2UgcHVlZGVuIGp1bnRhciB2YXJpb3MgZGUgZXN0b3MgYXRyaWJ1dG9zIGFsIG1pc21vIHRpZW1wbywgc2kgZXNvIHNlIGRlc2VhcmE6DQoNCmBgYHtyIGdlb21fcG9pbnQtY29sIHNoYXBlIHNpemUsIHdhcm5pbmc9RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjbGFzcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZHJ2LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGN5bCksDQogICAgICAgICAgICAgYWxwaGEgPSAwLjcpDQpgYGANCg0KU2UgcHVlZGVuIGFzb2NpYXIgdmFyaWFzIGNhcmFjdGVyw61zdGljYXMgYSBsYSBtaXNtYSB2YXJpYWJsZToNCg0KYGBge3IgZ2VvbV9wb2ludC1jb2wgc2hhcGUgc2l6ZTIsIHdhcm5pbmc9RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjbGFzcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gY2xhc3MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gY2xhc3MpLA0KICAgICAgICAgICAgIGFscGhhID0gMC43KQ0KYGBgDQoNCiMjIFZhcmlhcyBncsOhZmljYXMgZW4gdW5hIHNvbGEgY29uIGBwYXRjaHdvcmtgDQoNCkxvcyBncsOhZmljb3MgcXVlIHJlY2nDqW4gY3JlYW1vcyBwdWVkZW4gc2VyIGFsbWFjZW5hZG9zIGVuIHZhcmlhYmxlcy4gTGEgcGFxdWV0ZXLDrWEgcGF0Y2h3b3JrIG5vcyBwZXJtaXRlIGp1bnRhciBkb3MgbyBtw6FzIGdyw6FmaWNhcyBkZSBnZ3Bsb3QgZW4gdW5hIHNvbGEgaW1hZ2VuLiBSZXRvbWVtb3MgYWxndW5hcyBkZSBsYXMgZ3LDoWZpY2FzIGFudGVyaW9yZXMuDQoNCioqTk9UQToqKiAqRWwgbm9tYnJlIHNlIGVzY29nZSBhcmJpdHJhcmlhbWVudGUuKg0KDQpgYGB7ciBnZ3Bsb3RzLCBtZXNzYWdlPUZBTFNFfQ0KIyBMYXMgZ3LDoWZpY2FzIGEgcG9uZXIgZW4gdW5hIHNvbGEgaW1hZ2VuDQpnMSA8LSBnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpKw0KICBnZ3RpdGxlKCJMYSBncsOhZmljYSBtw6FzIGLDoXNpY2EiKQ0KDQpnMiA8LSBnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBjbGFzcykpKw0KICBnZ3RpdGxlKCJDb2xvciB2YXJpYWJsZSIpDQoNCmczIDwtIGdncGxvdChkYXRhID0gbXBnKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgY29sb3IgPSAiYmx1ZSIpKw0KICBnZ3RpdGxlKCJDb2xvciBmaWpvIikNCg0KZzQgPC0gZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGh3eSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY2xhc3MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGRydiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBjeWwpLA0KICAgICAgICAgICAgIGFscGhhID0gMC43KSArIA0KICBnZ3RpdGxlKCJDb2wsIGZvcm1hIHkgdGFtIHZhciwgYWxwaGEgZmlqYSIpDQpgYGANCg0KRWwgYWNvbW9kbyBzZSBwdWVkZSBndWFyZGFyIGVuIHVuYSB2YXJpYWJsZSB0YW1iacOpbi4gQ29uIGBwYXRjaHdvcmtgIGVzIGJhc3RhbnRlIGludHVpdGl2YSBsYSBtYW5lcmEgZGUgYWNvbW9kYXIgbGFzIGdyw6FmaWNhcy4NCg0KKiBgK2Agc2lydmUgcGFyYSBhZ3JlZ2FyIGdyw6FmaWNvcyBlbiBlc2EgbMOtbmVhICh0YW1iacOpbiBmdW5jaW9uYSB1dGlsaXphciBgfGApLg0KDQoqIGAvYCBzaXJ2ZSBwYXJhIGNyZWFyIHVuYSBudWV2YSBmaWxhLg0KDQpgYGB7ciBwYXRjaHdvcmsxLCBmaWcuaGVpZ2h0PTEyLGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0NCmZpZzEgPC0gZzEgLw0KICAoZzIgKyBnMykgLw0KICBnNA0KDQpmaWcxDQpgYGANCg0KU2UgcHVlZGVuIGFncmVnYXIgdMOtdHVsb3MgeSBzdWJ0w610dWxvcyBnbG9iYWxlcyBjb24gYHBsb3RfYW5ub3RhdGlvbigpYC4gVGFtYmnDqW4sIHNlIHB1ZWRlIGRlamFyIGVzcGFjaW9zIGVuIGJsYW5jbyB1c2FuZG8gYHBsb3Rfc3BhY2VyKClgOg0KDQpgYGB7ciBwYXRjaHdvcmsyLCBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMiwgd2FybmluZz1GQUxTRX0NCmZpZzEgKyANCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkdyw6FmaWNhcyBjb24gZ2dwbG90MiIsDQogICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJDYW1iaWFuZG8gbGEgZXN0w6l0aWNhIGRlIHZhcmlhcyBtYW5lcmFzIikNCg0KKGcxICsgcGxvdF9zcGFjZXIoKSkgLw0KICAoZzQpIC8NCiAgKGcyICsgZzMpICsNCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkdyw6FmaWNhcyBjb24gZ2dwbG90MiIsDQogICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJPdHJvIGFjb21vZG8gZGlzdGludG8iKQ0KDQoyICogNCArIDEwDQpgYGANCg0KIyMgVXNvIGRlIGZhY2V0YXMgey50YWJzZXR9DQoNCk90cmEgb3BjacOzbiBwYXJhIHBlcnNvbmFsaXphciBncsOhZmljYXMgZXMgdXRpbGl6YXIgZmFjZXRhcy4gRXN0byBkaXZpZGUgbnVlc3RybyBncsOhZmljbyBlbiB2YXJpb3Mgc3ViZ3LDoWZpY29zLCBkZSBhY3VlcmRvIGEgYWxndW5hIHZhcmlhYmxlIGVzcGVjaWZpY2FkYS4NCg0KIyMjIGBmYWNldF93cmFwKClgDQoNClBhcmEgc2VwYXJhciBsb3Mgc3ViZ3LDoWZpY29zIGNvbiBiYXNlIGVuIHVuYSB2YXJpYWJsZToNCg0KYGBge3IgZmFjZXRfd3JhcCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD02LGZpZy53aWR0aD04fQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBod3ksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY2xhc3MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZHJ2KSwNCiAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArIA0KICAgIGdndGl0bGUoIkZhY2V0YXMgcG9yIGNpbGluZHJhamUiKSArDQogIGZhY2V0X3dyYXAofiBjeWwpDQpgYGANCg0KIyMjIGBmYWNldF9ncmlkKClgDQoNCkxhcyBmYWNldGFzIHNlIHB1ZWRlbiBwb25lciBlbiBhbWJvcyBlamVzLCB1c2FuZG8gZG9zIHZhcmlhYmxlczoNCg0KYGBge3IgZmFjZXRfZ3JpZCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD02LGZpZy53aWR0aD04fQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGh3eSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY2xhc3MpLA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArIA0KICBnZ3RpdGxlKCJGYWNldGFzIHBvciB0cmFjY2nDs24geSBjaWxpbmRyYWplIikgKw0KICBmYWNldF9ncmlkKGN5bCB+IGRydikNCmBgYA0KDQojIyBHcsOhZmljYXMgZGUgbMOtbmVhcyB7LnRhYnNldH0NCg0KT3RybyB0aXBvIGRlIGdyw6FmaWNvIG11eSB1dGlsaXphZG8gZXMgZWwgZGUgbMOtbmVhcy4gVXNhcmVtb3Mgb3RybyBjb25qdW50byBkZSBkYXRvcyBwYXJhIGVzdG8uDQoNCmBgYHtyIGRhdG9zMiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmRhdGEoImVjb25vbWljcyIpDQpgYGANCg0KU2UgcHVlZGUgYWNjZWRlciBhIGxhIGRvY3VtZW50YWNpw7NuIGRlIGVzdGUgZGF0YXNldCAoeSBkZSBjdWFscXVpZXIgZnVuY2nDs24pLCBhIHRyYXbDqXMgZGUgbGEgZnVuY2nDs24gYGhlbHAoKWA6DQpgYGB7ciBoZWxwIGVjb24sIGV2YWw9RkFMU0V9DQpoZWxwKCJlY29ub21pY3MiKQ0KYGBgDQoNCg0KRXN0b3MgZGF0b3MgcXVlIGhlbW9zIHRyYWJhamFkbyBzb24gZGUgdGlwbyBgdGliYmxlYC4gUG9kZW1vcyBvYnNlcnZhciBsZ3VuYXMgZGlmZXJlbmNpYXMgZW50cmUgdW4gb2JqZXRvIGB0aWJibGVgIHkgdW4gYGRhdGEuZnJhbWVgIHRyYWRpY2lvbmFsOg0KDQojIyMgVGliYmxlDQoNClRlIG11ZXN0cmEgc29sbyBsYXMgcHJpbWVyYXMgMTAgZmlsYXMsIGFzw60gY29tbyBlbCB0aXBvIGRlIGRhdG9zIGRlIGNhZGEgY29sdW1uYS4gVGFtYmnDqW4gdGUgZGEgZW4gcmVzdW1lbiBsYSBkaW1lbnNpw7NuIGRlIGxhIHRhYmxhIChmaWxhcyB4IGNvbHVtbmFzKS4NCmBgYHtyIHRpYmJsZSwgZXZhbD1GQUxTRX0NCmVjb25vbWljcw0KIyBBIHRpYmJsZTogNTc0IHggNg0KIyAgICBkYXRlICAgICAgICAgcGNlICAgIHBvcCBwc2F2ZXJ0IHVlbXBtZWQgdW5lbXBsb3kNCiMgICAgPGRhdGU+ICAgICA8ZGJsPiAgPGRibD4gICA8ZGJsPiAgIDxkYmw+ICAgIDxkYmw+DQojICAxIDE5NjctMDctMDEgIDUwNy4gMTk4NzEyICAgIDEyLjYgICAgIDQuNSAgICAgMjk0NA0KIyAgMiAxOTY3LTA4LTAxICA1MTAuIDE5ODkxMSAgICAxMi42ICAgICA0LjcgICAgIDI5NDUNCiMgIDMgMTk2Ny0wOS0wMSAgNTE2LiAxOTkxMTMgICAgMTEuOSAgICAgNC42ICAgICAyOTU4DQojICA0IDE5NjctMTAtMDEgIDUxMi4gMTk5MzExICAgIDEyLjkgICAgIDQuOSAgICAgMzE0Mw0KIyAgNSAxOTY3LTExLTAxICA1MTcuIDE5OTQ5OCAgICAxMi44ICAgICA0LjcgICAgIDMwNjYNCiMgIDYgMTk2Ny0xMi0wMSAgNTI1LiAxOTk2NTcgICAgMTEuOCAgICAgNC44ICAgICAzMDE4DQojICA3IDE5NjgtMDEtMDEgIDUzMS4gMTk5ODA4ICAgIDExLjcgICAgIDUuMSAgICAgMjg3OA0KIyAgOCAxOTY4LTAyLTAxICA1MzQuIDE5OTkyMCAgICAxMi4zICAgICA0LjUgICAgIDMwMDENCiMgIDkgMTk2OC0wMy0wMSAgNTQ0LiAyMDAwNTYgICAgMTEuNyAgICAgNC4xICAgICAyODc3DQojIDEwIDE5NjgtMDQtMDEgIDU0NCAgMjAwMjA4ICAgIDEyLjMgICAgIDQuNiAgICAgMjcwOQ0KIyAuLi4gd2l0aCA1NjQgbW9yZSByb3dzDQpgYGANCg0KIyMjIERhdGEuZnJhbWUNCg0KYGBge3IgZGF0YS5mcmFtZSwgZXZhbD1GQUxTRX0NCmFzLmRhdGEuZnJhbWUoZWNvbm9taWNzKQ0KIyAgICAgICAgICAgZGF0ZSAgICBwY2UgICAgcG9wIHBzYXZlcnQgdWVtcG1lZCB1bmVtcGxveQ0KIyAxICAgMTk2Ny0wNy0wMSAgNTA2LjcgMTk4NzEyICAgIDEyLjYgICAgIDQuNSAgICAgMjk0NA0KIyAyICAgMTk2Ny0wOC0wMSAgNTA5LjggMTk4OTExICAgIDEyLjYgICAgIDQuNyAgICAgMjk0NQ0KIyAzICAgMTk2Ny0wOS0wMSAgNTE1LjYgMTk5MTEzICAgIDExLjkgICAgIDQuNiAgICAgMjk1OA0KIyA0ICAgMTk2Ny0xMC0wMSAgNTEyLjIgMTk5MzExICAgIDEyLjkgICAgIDQuOSAgICAgMzE0Mw0KIyA1ICAgMTk2Ny0xMS0wMSAgNTE3LjQgMTk5NDk4ICAgIDEyLjggICAgIDQuNyAgICAgMzA2Ng0KIyA2ICAgMTk2Ny0xMi0wMSAgNTI1LjEgMTk5NjU3ICAgIDExLjggICAgIDQuOCAgICAgMzAxOA0KIyA3ICAgMTk2OC0wMS0wMSAgNTMwLjkgMTk5ODA4ICAgIDExLjcgICAgIDUuMSAgICAgMjg3OA0KIyA4ICAgMTk2OC0wMi0wMSAgNTMzLjYgMTk5OTIwICAgIDEyLjMgICAgIDQuNSAgICAgMzAwMQ0KIyA5ICAgMTk2OC0wMy0wMSAgNTQ0LjMgMjAwMDU2ICAgIDExLjcgICAgIDQuMSAgICAgMjg3Nw0KIyAxMCAgMTk2OC0wNC0wMSAgNTQ0LjAgMjAwMjA4ICAgIDEyLjMgICAgIDQuNiAgICAgMjcwOQ0KIyAxMSAgMTk2OC0wNS0wMSAgNTQ5LjggMjAwMzYxICAgIDEyLjAgICAgIDQuNCAgICAgMjc0MA0KIyAxMiAgMTk2OC0wNi0wMSAgNTU2LjMgMjAwNTM2ICAgIDExLjcgICAgIDQuNCAgICAgMjkzOA0KIyAxMyAgMTk2OC0wNy0wMSAgNTYzLjIgMjAwNzA2ICAgIDEwLjcgICAgIDQuNSAgICAgMjg4Mw0KIyAxNCAgMTk2OC0wOC0wMSAgNTY3LjAgMjAwODk4ICAgIDEwLjUgICAgIDQuMiAgICAgMjc2OA0KIyAxNSAgMTk2OC0wOS0wMSAgNTY4LjIgMjAxMDk1ICAgIDEwLjYgICAgIDQuNiAgICAgMjY4Ng0KIyAxNiAgMTk2OC0xMC0wMSAgNTcxLjYgMjAxMjkwICAgIDEwLjggICAgIDQuOCAgICAgMjY4OQ0KIyAxNyAgMTk2OC0xMS0wMSAgNTc2LjcgMjAxNDY2ICAgIDEwLjYgICAgIDQuNCAgICAgMjcxNQ0KIyAxOCAgMTk2OC0xMi0wMSAgNTc2LjUgMjAxNjIxICAgIDExLjEgICAgIDQuNCAgICAgMjY4NQ0KIyAxOSAgMTk2OS0wMS0wMSAgNTgzLjUgMjAxNzYwICAgIDEwLjMgICAgIDQuNCAgICAgMjcxOA0KIyAyMCAgMTk2OS0wMi0wMSAgNTg4LjcgMjAxODgxICAgICA5LjcgICAgIDQuOSAgICAgMjY5Mg0KIyAyMSAgMTk2OS0wMy0wMSAgNTg4LjkgMjAyMDIzICAgIDEwLjIgICAgIDQuMCAgICAgMjcxMg0KIyAyMiAgMTk2OS0wNC0wMSAgNTkzLjkgMjAyMTYxICAgICA5LjcgICAgIDQuMCAgICAgMjc1OA0KIyAyMyAgMTk2OS0wNS0wMSAgNjAwLjMgMjAyMzMxICAgIDEwLjEgICAgIDQuMiAgICAgMjcxMw0KIyAyNCAgMTk2OS0wNi0wMSAgNjAwLjkgMjAyNTA3ICAgIDExLjEgICAgIDQuNCAgICAgMjgxNg0KIyAyNSAgMTk2OS0wNy0wMSAgNjAyLjcgMjAyNjc3ICAgIDExLjggICAgIDQuNCAgICAgMjg2OA0KIyAyNiAgMTk2OS0wOC0wMSAgNjA5LjkgMjAyODc3ICAgIDExLjUgICAgIDQuNCAgICAgMjg1Ng0KIyAyNyAgMTk2OS0wOS0wMSAgNjEzLjIgMjAzMDkwICAgIDExLjYgICAgIDQuNyAgICAgMzA0MA0KIyAyOCAgMTk2OS0xMC0wMSAgNjE4LjUgMjAzMzAyICAgIDExLjQgICAgIDQuNSAgICAgMzA0OQ0KIyAyOSAgMTk2OS0xMS0wMSAgNjIwLjUgMjAzNTAwICAgIDExLjYgICAgIDQuOCAgICAgMjg1Ng0KIyAzMCAgMTk2OS0xMi0wMSAgNjIyLjggMjAzNjc1ICAgIDExLjggICAgIDQuNiAgICAgMjg4NA0KIyAzMSAgMTk3MC0wMS0wMSAgNjI4LjcgMjAzODQ5ICAgIDExLjggICAgIDQuNiAgICAgMzIwMQ0KIyAzMiAgMTk3MC0wMi0wMSAgNjM0LjAgMjA0MDA4ICAgIDExLjcgICAgIDQuNSAgICAgMzQ1Mw0KIyAzMyAgMTk3MC0wMy0wMSAgNjMyLjMgMjA0MTU2ICAgIDEyLjQgICAgIDQuNiAgICAgMzYzNQ0KIyAzNCAgMTk3MC0wNC0wMSAgNjM2LjAgMjA0NDAxICAgIDEzLjMgICAgIDQuMSAgICAgMzc5Nw0KIyAzNSAgMTk3MC0wNS0wMSAgNjQyLjQgMjA0NjA3ICAgIDEyLjQgICAgIDQuNyAgICAgMzkxOQ0KIyAzNiAgMTk3MC0wNi0wMSAgNjQ2LjMgMjA0ODMwICAgIDEyLjMgICAgIDQuOSAgICAgNDA3MQ0KIyAzNyAgMTk3MC0wNy0wMSAgNjQ4LjUgMjA1MDUyICAgIDEzLjUgICAgIDUuMSAgICAgNDE3NQ0KIyAzOCAgMTk3MC0wOC0wMSAgNjUyLjkgMjA1Mjk1ICAgIDEzLjQgICAgIDUuNCAgICAgNDI1Ng0KIyAzOSAgMTk3MC0wOS0wMSAgNjU5LjEgMjA1NTQwICAgIDEyLjkgICAgIDUuMiAgICAgNDQ1Ng0KIyA0MCAgMTk3MC0xMC0wMSAgNjU4LjMgMjA1Nzg4ICAgIDEzLjEgICAgIDUuMiAgICAgNDU5MQ0KIyA0MSAgMTk3MC0xMS0wMSAgNjU2LjYgMjA2MDI0ICAgIDEzLjYgICAgIDUuNiAgICAgNDg5OA0KIyA0MiAgMTk3MC0xMi0wMSAgNjY1LjYgMjA2MjM4ICAgIDEzLjIgICAgIDUuOSAgICAgNTA3Ng0KIyA0MyAgMTk3MS0wMS0wMSAgNjc2LjEgMjA2NDY2ICAgIDEzLjMgICAgIDYuMiAgICAgNDk4Ng0KIyA0NCAgMTk3MS0wMi0wMSAgNjc5LjQgMjA2NjY4ICAgIDEzLjMgICAgIDYuMyAgICAgNDkwMw0KIyA0NSAgMTk3MS0wMy0wMSAgNjgyLjAgMjA2ODU1ICAgIDEzLjUgICAgIDYuNCAgICAgNDk4Nw0KIyA0NiAgMTk3MS0wNC0wMSAgNjg4LjggMjA3MDY1ICAgIDEzLjIgICAgIDYuNSAgICAgNDk1OQ0KIyA0NyAgMTk3MS0wNS0wMSAgNjkxLjEgMjA3MjYwICAgIDEzLjYgICAgIDYuNyAgICAgNDk5Ng0KIyA0OCAgMTk3MS0wNi0wMSAgNjk5LjggMjA3NDYyICAgIDE0LjcgICAgIDUuNyAgICAgNDk0OQ0KIyA0OSAgMTk3MS0wNy0wMSAgNjk4LjkgMjA3NjYxICAgIDEzLjggICAgIDYuMiAgICAgNTAzNQ0KIyA1MCAgMTk3MS0wOC0wMSAgNzA0LjkgMjA3ODgxICAgIDEzLjYgICAgIDYuNCAgICAgNTEzNA0KIyA1MSAgMTk3MS0wOS0wMSAgNzEzLjAgMjA4MTE0ICAgIDEzLjMgICAgIDUuOCAgICAgNTA0Mg0KIyA1MiAgMTk3MS0xMC0wMSAgNzE1LjggMjA4MzQ1ICAgIDEzLjMgICAgIDYuNSAgICAgNDk1NA0KIyA1MyAgMTk3MS0xMS0wMSAgNzIwLjkgMjA4NTU1ICAgIDEzLjEgICAgIDYuNCAgICAgNTE2MQ0KIyA1NCAgMTk3MS0xMi0wMSAgNzI4LjQgMjA4NzQwICAgIDEzLjAgICAgIDYuMiAgICAgNTE1NA0KIyA1NSAgMTk3Mi0wMS0wMSAgNzMxLjUgMjA4OTE3ICAgIDEyLjUgICAgIDYuMiAgICAgNTAxOQ0KIyA1NiAgMTk3Mi0wMi0wMSAgNzM2LjIgMjA5MDYxICAgIDEyLjggICAgIDYuNiAgICAgNDkyOA0KIyA1NyAgMTk3Mi0wMy0wMSAgNzQ5LjIgMjA5MjEyICAgIDExLjggICAgIDYuNiAgICAgNTAzOA0KIyA1OCAgMTk3Mi0wNC0wMSAgNzUyLjUgMjA5Mzg2ICAgIDExLjUgICAgIDYuNyAgICAgNDk1OQ0KIyA1OSAgMTk3Mi0wNS0wMSAgNzU4LjAgMjA5NTQ1ICAgIDExLjcgICAgIDYuNiAgICAgNDkyMg0KIyA2MCAgMTk3Mi0wNi0wMSAgNzYxLjYgMjA5NzI1ICAgIDExLjcgICAgIDUuNCAgICAgNDkyMw0KIyA2MSAgMTk3Mi0wNy0wMSAgNzY5LjkgMjA5ODk2ICAgIDExLjcgICAgIDYuMSAgICAgNDkxMw0KIyA2MiAgMTk3Mi0wOC0wMSAgNzc2LjMgMjEwMDc1ICAgIDEyLjAgICAgIDYuMCAgICAgNDkzOQ0KIyA2MyAgMTk3Mi0wOS0wMSAgNzgxLjEgMjEwMjc4ICAgIDEyLjIgICAgIDUuNiAgICAgNDg0OQ0KIyA2NCAgMTk3Mi0xMC0wMSAgNzk0LjkgMjEwNDc5ICAgIDEzLjAgICAgIDUuNyAgICAgNDg3NQ0KIyA2NSAgMTk3Mi0xMS0wMSAgODAwLjUgMjEwNjU2ICAgIDEzLjYgICAgIDUuNyAgICAgNDYwMg0KIyA2NiAgMTk3Mi0xMi0wMSAgODA2LjEgMjEwODIxICAgIDEzLjcgICAgIDYuMSAgICAgNDU0Mw0KIyA2NyAgMTk3My0wMS0wMSAgODE2LjUgMjEwOTg1ICAgIDEyLjQgICAgIDUuNyAgICAgNDMyNg0KIyA2OCAgMTk3My0wMi0wMSAgODI1LjggMjExMTIwICAgIDEyLjUgICAgIDUuMiAgICAgNDQ1Mg0KIyA2OSAgMTk3My0wMy0wMSAgODMyLjggMjExMjU0ICAgIDEyLjcgICAgIDUuNSAgICAgNDM5NA0KIyA3MCAgMTk3My0wNC0wMSAgODM1LjcgMjExNDIwICAgIDEzLjIgICAgIDUuMCAgICAgNDQ1OQ0KIyA3MSAgMTk3My0wNS0wMSAgODQxLjYgMjExNTc3ICAgIDEzLjIgICAgIDQuOSAgICAgNDMyOQ0KIyA3MiAgMTk3My0wNi0wMSAgODQ0LjMgMjExNzQ2ICAgIDEzLjYgICAgIDUuMCAgICAgNDM2Mw0KIyA3MyAgMTk3My0wNy0wMSAgODU0LjEgMjExOTA5ICAgIDEzLjIgICAgIDUuMiAgICAgNDMwNQ0KIyA3NCAgMTk3My0wOC0wMSAgODUzLjMgMjEyMDkyICAgIDEzLjkgICAgIDQuOSAgICAgNDMwNQ0KIyA3NSAgMTk3My0wOS0wMSAgODY5LjIgMjEyMjg5ICAgIDEzLjEgICAgIDUuNCAgICAgNDM1MA0KIyA3NiAgMTk3My0xMC0wMSAgODY4LjIgMjEyNDc1ICAgIDE0LjQgICAgIDUuNSAgICAgNDE0NA0KIyA3NyAgMTk3My0xMS0wMSAgODc2LjkgMjEyNjM0ICAgIDE0LjQgICAgIDUuMSAgICAgNDM5Ng0KIyA3OCAgMTk3My0xMi0wMSAgODc2LjYgMjEyNzg1ICAgIDE0LjggICAgIDQuNyAgICAgNDQ4OQ0KIyA3OSAgMTk3NC0wMS0wMSAgODg0LjUgMjEyOTMyICAgIDE0LjMgICAgIDUuMCAgICAgNDY0NA0KIyA4MCAgMTk3NC0wMi0wMSAgODg5LjcgMjEzMDc0ICAgIDE0LjIgICAgIDUuMSAgICAgNDczMQ0KIyA4MSAgMTk3NC0wMy0wMSAgOTAxLjQgMjEzMjExICAgIDEzLjQgICAgIDQuOCAgICAgNDYzNA0KIyA4MiAgMTk3NC0wNC0wMSAgOTEwLjggMjEzMzYxICAgIDEzLjEgICAgIDUuMCAgICAgNDYxOA0KIyA4MyAgMTk3NC0wNS0wMSAgOTIyLjQgMjEzNTEzICAgIDEyLjggICAgIDQuNiAgICAgNDcwNQ0KIyA4NCAgMTk3NC0wNi0wMSAgOTI4LjAgMjEzNjg2ICAgIDEyLjggICAgIDUuMyAgICAgNDkyNw0KIyA4NSAgMTk3NC0wNy0wMSAgOTM3LjkgMjEzODU0ICAgIDEyLjggICAgIDUuNyAgICAgNTA2Mw0KIyA4NiAgMTk3NC0wOC0wMSAgOTU0LjggMjE0MDQyICAgIDEyLjEgICAgIDUuMCAgICAgNTAyMg0KIyA4NyAgMTk3NC0wOS0wMSAgOTU1LjEgMjE0MjQ2ICAgIDEyLjkgICAgIDUuMyAgICAgNTQzNw0KIyA4OCAgMTk3NC0xMC0wMSAgOTU5LjIgMjE0NDUxICAgIDEzLjQgICAgIDUuNSAgICAgNTUyMw0KIyA4OSAgMTk3NC0xMS0wMSAgOTU2LjIgMjE0NjI1ICAgIDEzLjggICAgIDUuMiAgICAgNjE0MA0KIyA5MCAgMTk3NC0xMi0wMSAgOTYxLjggMjE0NzgyICAgIDE0LjAgICAgIDUuNyAgICAgNjYzNg0KIyA5MSAgMTk3NS0wMS0wMSAgOTc1LjYgMjE0OTMxICAgIDEzLjIgICAgIDYuMyAgICAgNzUwMQ0KIyA5MiAgMTk3NS0wMi0wMSAgOTg5LjQgMjE1MDY1ICAgIDEyLjUgICAgIDcuMSAgICAgNzUyMA0KIyA5MyAgMTk3NS0wMy0wMSAgOTkwLjYgMjE1MTk4ICAgIDEyLjcgICAgIDcuMiAgICAgNzk3OA0KIyA5NCAgMTk3NS0wNC0wMSAgOTk1LjAgMjE1MzUzICAgIDE0LjIgICAgIDguNyAgICAgODIxMA0KIyA5NSAgMTk3NS0wNS0wMSAxMDE4LjkgMjE1NTIzICAgIDE3LjMgICAgIDkuNCAgICAgODQzMw0KIyA5NiAgMTk3NS0wNi0wMSAxMDI2LjggMjE1NzY4ICAgIDE0LjMgICAgIDguOCAgICAgODIyMA0KIyA5NyAgMTk3NS0wNy0wMSAxMDM5LjggMjE1OTczICAgIDEyLjYgICAgIDguNiAgICAgODEyNw0KIyA5OCAgMTk3NS0wOC0wMSAxMDQ3LjAgMjE2MTk1ICAgIDEzLjAgICAgIDkuMiAgICAgNzkyOA0KIyA5OSAgMTk3NS0wOS0wMSAxMDU0LjggMjE2MzkzICAgIDEzLjAgICAgIDkuMiAgICAgNzkyMw0KIyAxMDAgMTk3NS0xMC0wMSAxMDYwLjkgMjE2NTg3ICAgIDEzLjQgICAgIDguNiAgICAgNzg5Nw0KIyAxMDEgMTk3NS0xMS0wMSAxMDc1LjggMjE2NzcxICAgIDEyLjcgICAgIDkuNSAgICAgNzc5NA0KIyAxMDIgMTk3NS0xMi0wMSAxMDkyLjEgMjE2OTMxICAgIDEyLjAgICAgIDkuMCAgICAgNzc0NA0KIyAxMDMgMTk3Ni0wMS0wMSAxMTA3LjEgMjE3MDk1ICAgIDExLjcgICAgIDkuMCAgICAgNzUzNA0KIyAxMDQgMTk3Ni0wMi0wMSAxMTA3LjcgMjE3MjQ5ICAgIDEyLjMgICAgIDguMiAgICAgNzMyNg0KIyAxMDUgMTk3Ni0wMy0wMSAxMTE0LjkgMjE3MzgxICAgIDEyLjIgICAgIDguNyAgICAgNzIzMA0KIyAxMDYgMTk3Ni0wNC0wMSAxMTI1LjQgMjE3NTI4ICAgIDExLjcgICAgIDguMiAgICAgNzMzMA0KIyAxMDcgMTk3Ni0wNS0wMSAxMTIyLjcgMjE3Njg1ICAgIDEyLjMgICAgIDguMyAgICAgNzA1Mw0KIyAxMDggMTk3Ni0wNi0wMSAxMTQwLjUgMjE3ODYxICAgIDExLjQgICAgIDcuOCAgICAgNzMyMg0KIyAxMDkgMTk3Ni0wNy0wMSAxMTQ5LjYgMjE4MDM1ICAgIDExLjcgICAgIDcuNyAgICAgNzQ5MA0KIyAxMTAgMTk3Ni0wOC0wMSAxMTU4LjAgMjE4MjMzICAgIDExLjcgICAgIDcuOSAgICAgNzUxOA0KIyAxMTEgMTk3Ni0wOS0wMSAxMTY4LjggMjE4NDQwICAgIDExLjQgICAgIDcuOCAgICAgNzM4MA0KIyAxMTIgMTk3Ni0xMC0wMSAxMTc2LjggMjE4NjQ0ICAgIDExLjEgICAgIDcuNyAgICAgNzQzMA0KIyAxMTMgMTk3Ni0xMS0wMSAxMTg5LjAgMjE4ODM0ICAgIDExLjQgICAgIDguNCAgICAgNzYyMA0KIyAxMTQgMTk3Ni0xMi0wMSAxMjExLjUgMjE5MDA2ICAgIDEwLjYgICAgIDguMCAgICAgNzU0NQ0KIyAxMTUgMTk3Ny0wMS0wMSAxMjE1LjAgMjE5MTc5ICAgIDEwLjYgICAgIDcuNSAgICAgNzI4MA0KIyAxMTYgMTk3Ny0wMi0wMSAxMjMxLjMgMjE5MzQ0ICAgICA5LjMgICAgIDcuMiAgICAgNzQ0Mw0KIyAxMTcgMTk3Ny0wMy0wMSAxMjM4LjMgMjE5NTA0ICAgIDEwLjUgICAgIDcuMiAgICAgNzMwNw0KIyAxMTggMTk3Ny0wNC0wMSAxMjQ3LjMgMjE5Njg0ICAgIDEwLjUgICAgIDcuMyAgICAgNzA1OQ0KIyAxMTkgMTk3Ny0wNS0wMSAxMjU3LjEgMjE5ODU5ICAgIDEwLjMgICAgIDcuOSAgICAgNjkxMQ0KIyAxMjAgMTk3Ny0wNi0wMSAxMjYzLjYgMjIwMDQ2ICAgIDEwLjYgICAgIDYuMiAgICAgNzEzNA0KIyAxMjEgMTk3Ny0wNy0wMSAxMjgwLjUgMjIwMjM5ICAgIDEwLjUgICAgIDcuMSAgICAgNjgyOQ0KIyAxMjIgMTk3Ny0wOC0wMSAxMjg1LjcgMjIwNDU4ICAgIDEwLjkgICAgIDcuMCAgICAgNjkyNQ0KIyAxMjMgMTk3Ny0wOS0wMSAxMjk0LjUgMjIwNjg4ICAgIDExLjEgICAgIDYuNyAgICAgNjc1MQ0KIyAxMjQgMTk3Ny0xMC0wMSAxMzExLjQgMjIwOTA0ICAgIDExLjAgICAgIDYuOSAgICAgNjc2Mw0KIyAxMjUgMTk3Ny0xMS0wMSAxMzI3LjAgMjIxMTA5ICAgIDExLjIgICAgIDcuMCAgICAgNjgxNQ0KIyAxMjYgMTk3Ny0xMi0wMSAxMzM2LjAgMjIxMzAzICAgIDExLjQgICAgIDYuOCAgICAgNjM4Ng0KIyAxMjcgMTk3OC0wMS0wMSAxMzI5LjUgMjIxNDc3ICAgIDExLjkgICAgIDYuNSAgICAgNjQ4OQ0KIyAxMjggMTk3OC0wMi0wMSAxMzU1LjEgMjIxNjI5ICAgIDExLjEgICAgIDYuNyAgICAgNjMxOA0KIyAxMjkgMTk3OC0wMy0wMSAxMzc3LjUgMjIxNzkyICAgIDExLjAgICAgIDYuMiAgICAgNjMzNw0KIyAxMzAgMTk3OC0wNC0wMSAxMzk2LjQgMjIxOTkxICAgIDEwLjggICAgIDYuMSAgICAgNjE4MA0KIyAxMzEgMTk3OC0wNS0wMSAxNDEyLjAgMjIyMTc2ICAgIDEwLjMgICAgIDUuNyAgICAgNjEyNw0KIyAxMzIgMTk3OC0wNi0wMSAxNDI1LjggMjIyMzc5ICAgIDEwLjAgICAgIDYuMCAgICAgNjAyOA0KIyAxMzMgMTk3OC0wNy0wMSAxNDI2LjggMjIyNTg1ICAgIDEwLjkgICAgIDUuOCAgICAgNjMwOQ0KIyAxMzQgMTk3OC0wOC0wMSAxNDQ3LjAgMjIyODA1ICAgIDEwLjUgICAgIDUuOCAgICAgNjA4MA0KIyAxMzUgMTk3OC0wOS0wMSAxNDUyLjkgMjIzMDUzICAgIDEwLjYgICAgIDUuNiAgICAgNjEyNQ0KIyAxMzYgMTk3OC0xMC0wMSAxNDY2LjkgMjIzMjcxICAgIDEwLjcgICAgIDUuOSAgICAgNTk0Nw0KIyAxMzcgMTk3OC0xMS0wMSAxNDgwLjYgMjIzNDc3ICAgIDEwLjUgICAgIDUuNSAgICAgNjA3Nw0KIyAxMzggMTk3OC0xMi0wMSAxNDk2LjUgMjIzNjcwICAgIDEwLjQgICAgIDUuNiAgICAgNjIyOA0KIyAxMzkgMTk3OS0wMS0wMSAxNTAyLjQgMjIzODY1ICAgIDExLjEgICAgIDUuOSAgICAgNjEwOQ0KIyAxNDAgMTk3OS0wMi0wMSAxNTE3LjggMjI0MDUzICAgIDExLjEgICAgIDUuOSAgICAgNjE3Mw0KIyAxNDEgMTk3OS0wMy0wMSAxNTMxLjIgMjI0MjM1ICAgIDExLjIgICAgIDUuOSAgICAgNjEwOQ0KIyAxNDIgMTk3OS0wNC0wMSAxNTM4LjQgMjI0NDM4ICAgIDExLjAgICAgIDUuNCAgICAgNjA2OQ0KIyAxNDMgMTk3OS0wNS0wMSAxNTU4LjggMjI0NjMyICAgIDEwLjMgICAgIDUuNiAgICAgNTg0MA0KIyAxNDQgMTk3OS0wNi0wMSAxNTc1LjcgMjI0ODQzICAgICA5LjkgICAgIDUuNiAgICAgNTk1OQ0KIyAxNDUgMTk3OS0wNy0wMSAxNTg2LjEgMjI1MDU1ICAgIDEwLjYgICAgIDUuOSAgICAgNTk5Ng0KIyAxNDYgMTk3OS0wOC0wMSAxNjE1LjYgMjI1Mjk1ICAgICA5LjcgICAgIDQuOCAgICAgNjMyMA0KIyAxNDcgMTk3OS0wOS0wMSAxNjMzLjkgMjI1NTQ3ICAgICA5LjQgICAgIDUuNSAgICAgNjE5MA0KIyAxNDggMTk3OS0xMC0wMSAxNjQxLjYgMjI1ODAxICAgICA5LjcgICAgIDUuNSAgICAgNjI5Ng0KIyAxNDkgMTk3OS0xMS0wMSAxNjU3LjMgMjI2MDI3ICAgICA5LjcgICAgIDUuMyAgICAgNjIzOA0KIyAxNTAgMTk3OS0xMi0wMSAxNjY2LjMgMjI2MjQzICAgIDEwLjEgICAgIDUuNyAgICAgNjMyNQ0KIyAxNTEgMTk4MC0wMS0wMSAxNjk3LjMgMjI2NDUxICAgICA5LjkgICAgIDUuMyAgICAgNjY4Mw0KIyAxNTIgMTk4MC0wMi0wMSAxNzAxLjQgMjI2NjU2ICAgIDEwLjEgICAgIDUuOCAgICAgNjcwMg0KIyAxNTMgMTk4MC0wMy0wMSAxNzA4LjIgMjI2ODQ5ICAgIDEwLjIgICAgIDYuMCAgICAgNjcyOQ0KIyAxNTQgMTk4MC0wNC0wMSAxNjk1LjIgMjI3MDYxICAgIDExLjMgICAgIDUuOCAgICAgNzM1OA0KIyAxNTUgMTk4MC0wNS0wMSAxNzAwLjEgMjI3MjUxICAgIDExLjQgICAgIDUuNyAgICAgNzk4NA0KIyAxNTYgMTk4MC0wNi0wMSAxNzE4LjggMjI3NTIyICAgIDExLjIgICAgIDYuNCAgICAgODA5OA0KIyAxNTcgMTk4MC0wNy0wMSAxNzQ3LjEgMjI3NzI2ICAgIDExLjMgICAgIDcuMCAgICAgODM2Mw0KIyAxNTggMTk4MC0wOC0wMSAxNzYzLjggMjI3OTUzICAgIDExLjMgICAgIDcuNSAgICAgODI4MQ0KIyAxNTkgMTk4MC0wOS0wMSAxNzgwLjUgMjI4MTg2ICAgIDExLjcgICAgIDcuNyAgICAgODAyMQ0KIyAxNjAgMTk4MC0xMC0wMSAxODE3LjEgMjI4NDE3ICAgIDExLjMgICAgIDcuNSAgICAgODA4OA0KIyAxNjEgMTk4MC0xMS0wMSAxODI2LjggMjI4NjEyICAgIDExLjYgICAgIDcuNyAgICAgODAyMw0KIyAxNjIgMTk4MC0xMi0wMSAxODUxLjcgMjI4Nzc5ICAgIDExLjQgICAgIDcuNSAgICAgNzcxOA0KIyAxNjMgMTk4MS0wMS0wMSAxODcwLjAgMjI4OTM3ICAgIDEwLjkgICAgIDcuNCAgICAgODA3MQ0KIyAxNjQgMTk4MS0wMi0wMSAxODg0LjIgMjI5MDcxICAgIDEwLjggICAgIDcuMSAgICAgODA1MQ0KIyAxNjUgMTk4MS0wMy0wMSAxOTAyLjkgMjI5MjI0ICAgIDEwLjggICAgIDcuMSAgICAgNzk4Mg0KIyAxNjYgMTk4MS0wNC0wMSAxOTA0LjQgMjI5NDAzICAgIDEwLjkgICAgIDcuNCAgICAgNzg2OQ0KIyAgWyByZWFjaGVkICdtYXgnIC8gZ2V0T3B0aW9uKCJtYXgucHJpbnQiKSAtLSBvbWl0dGVkIDQwOCByb3dzIF0NCmBgYA0KDQojIyB7LX0NCg0KKioqDQoNCkdyYWZpcXVlbW9zIGVsIGRlc2VtcGxlbyBhIGxvIGxhcmdvIGRlbCB0aWVtcG8uDQoNCmBgYHtyIGdlb21fbGluZSwgbWVzc2FnZT1GQUxTRX0NCmdncGxvdChlY29ub21pY3MsDQogICAgICAgYWVzKHggPSBkYXRlLCB5ID0gdW5lbXBsb3kpKSArIA0KICBnZW9tX2xpbmUoKQ0KYGBgDQoNCkZpbHRyYW5kbyBsb3MgZGF0b3MgeSBhw7FhZGllbmRvIGRvcyBjYXBhcyBkZSBncsOhZmljb3MgKHB1bnRvcyB5IGzDrW5lYXMpOg0KDQpgYGB7ciBnZW9tX2xpbmUgKyBwb2ludCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdncGxvdChlY29ub21pY3MgJT4lIGZpbHRlcih5ZWFyKGRhdGUpPj0yMDA2KSwNCiAgICAgICBhZXMoeCA9IGRhdGUsIHkgPSB1bmVtcGxveSkpICsgDQogIGdlb21fbGluZShjb2xvciA9ICJyZWQiKSArIA0KICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9ImZvcmVzdGdyZWVuIikNCmBgYA0KU2Vyw61hIGV4YWN0YW1lbnRlIGVsIG1pc21vIHJlc3VsdGFkbyBzaSBkZWZpbmltb3MgZWwgYGFlcygpYCBkZW50cm8gZGUgY2FkYSB1bm8gZGUgbG9zIGBnZW9tc2A6DQoNCmBgYHtyIGdlb21fbGluZSArIHBvaW50IGFlcyBpbmRlcGVuZGVudH0NCmdncGxvdChlY29ub21pY3MgJT4lIGZpbHRlcih5ZWFyKGRhdGUpPj0yMDA2KSkgKyANCiAgZ2VvbV9saW5lKGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95KSwgY29sb3IgPSAicmVkIikgKyANCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRhdGUsIHkgPSB1bmVtcGxveSksIHNpemUgPSAxLCBjb2xvciA9ImZvcmVzdGdyZWVuIikNCmBgYA0KDQpTZSBwdWVkZW4gY3JlYXIgc3VzIHByb3BpYXMgYHRpYmJsZXNgIGRpcmVjdGFtZW50ZSBlbiAqKlIqKiBjb24gbGEgZnVuY2nDs24gYHRpYmJsZSgpYDoNCg0KYGBge3J9DQp0aWJibGUoZmVjaGEgPSBjKCIzMSBhdWcgMjAiLCIxLXNlcC0yMCIsIjAyLzkvMjAyMCIpLA0KICAgICAgIGRvbGFyID0gYygyNCwyNC4zLDI1KSwNCiAgICAgICBgZGlhIGNhbHVyb3NvYCA9IGMoMSwgMCwgMSkpICU+JQ0KICBtdXRhdGUoZmVjaGEgPSBkbXkoZmVjaGEpLCANCiAgICAgICAgIGBkaWEgY2FsdXJvc29gID0gYXMuaW50ZWdlcihgZGlhIGNhbHVyb3NvYCksDQogICAgICAgICBgZGlhIGNhbHVyb3NvIDJgID0gYXMubG9naWNhbChgZGlhIGNhbHVyb3NvYCkpDQoNCiMgRXN0byBtYXJjYXLDrWEgdW4gZXJyb3I6DQojIDIgPC0gNA0KIyBTZSBwdWVkZSBoYWNlciBlc3RvLCBwZXJvIE5PIGVzIHJlY29tZW5kYWJsZQ0KYDJgIDwtIDQNCmAyYA0KYGBgDQoNCg0KIyBUcmFuc2Zvcm1hY2nDs24gZGUgZGF0b3MgY29uIGBkcGx5cmANCg0KVXRpbGl6YXJlbW9zIGxvcyBkYXRvcyBkZSBgZ2FwbWluZGVyYCBwYXJhIHJldmlzYXIgdmFyaW9zIGVqZW1wbG9zLiBFeHBsb3JhbmRvIGxhIHRhYmxhLCB2ZW1vcyBxdWUgY29udGllbmUgMSw3MDQgZmlsYXMgY29uIDYgY29sdW1uYXM6DQoNCiogUGHDrXMgYGNvdW50cnlgDQoqIENvbnRpbmVudGUgYGNvbnRpbmVudGANCiogQcOxbyBgeWVhcmANCiogRXNwZXJhbnphIGRlIHZpZGEgKGVuIGHDsW9zKSBgbGlmZUV4cGANCiogUG9ibGFjacOzbiBgcG9wYA0KKiBQSUIgcGVyIGPDoXBpdGEgKGVuIFVTRCwgYWp1c3RhZG9zIHBvciBsYSBpbmZsYWNpw7NuKSBgZ2RwUGVyY2FwYA0KDQpgYGB7ciBnYXBtaW5kZXJ9DQpkYXRhKGdhcG1pbmRlcikNCmdhcG1pbmRlcg0KDQpnYXBtaW5kZXIgJT4lIA0KICBkaXN0aW5jdChjb3VudHJ5KSAlPiUgDQogIG5yb3coKQ0KDQojIGxldmVscyhnYXBtaW5kZXIkY291bnRyeSkNCmBgYA0KDQpTaSBxdWlzacOpcmFtb3MgZmlsdHJhciBsYSB0YWJsYSBwYXJhIG1hbnRlbmVyIHPDs2xvIGxvcyBwYcOtc2VzIGFzacOhdGljb3MsIGxvIHBvZHLDrWFtb3MgbG9ncmFyIGNvbiBlbCB2ZXJibyBgZmlsdGVyKClgLiBPcGNpb25hbG1lbnRlLCBwb2Ryw61hbW9zIHZhbGlkYXIgY29uIGBkaXN0aW5jdCgpYCBzaSBudWVzdHJvIGZpbHRybyBsb2dyw7MgZWwgb2JqZXRpdm86DQoNCmBgYHtyIGdhcCBmaWx0ZXIgY29udGluZW50fQ0KIyBQYXJhIHF1ZWRhcm5vcyBzb2xvIGNvbiBwYcOtc2VzIGFzacOhdGljb3MNCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb250aW5lbnQgPT0gIkFzaWEiKQ0KIyBWYWxpZGFjacOzbg0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQXNpYSIpICU+JSANCiAgZGlzdGluY3QoY29udGluZW50KQ0KDQpnYXBtaW5kZXIgJT4lIA0KICBkaXN0aW5jdChjb250aW5lbnQpDQpgYGANCg0KVmVtb3MgcXVlIGxhcyBmaWxhcyBkZSBsYSB0YWJsYSBzZSByZWR1amVyb24gKGEgMzk2KSB5IHF1ZSwgZWZlY3RpdmFtZW50ZSwgbG9ncmFtb3MgZWwgb2JqZXRpdm8gZGUgbWFudGVuZXIgcHVyb3MgcGHDrXNlcyBkZSBBc2lhLg0KDQpQb2RlbW9zIG9yZGVuYXIgdW5hIHRhYmxhIGNvbiByZXNwZWN0byBhIHVuYSBkZSBzdXMgdmFyaWFibGVzIGNvbiBgYXJyYW5nZSgpYC4gUG9yIGRlZsOhdWx0LCBlbCBvcmRlbiBzZXLDoSBhc2NlbmRlbnRlLiBTaSBzZSBkZXNlYSBlbiBvcmRlbiBkZXNjZW5kZW50ZSwgYWdyZWdhbW9zIGBkZXNjKClgLiBQcm9iZW1vcyBtb3N0cmFuZG8gYSBsb3MgcGHDrXNlcyBxdWUgdGllbmVuIGxhIG1heW9yIHBvYmxhY2nDs24gZW4gZWwgYcOxbyAyMDA3Lg0KDQpgYGB7ciBnYXAgYXJyYW5nZWR9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUgDQogIGFycmFuZ2UoZGVzYyhwb3ApKQ0KYGBgDQpQYXJhIHF1ZWRhcm5vcyBjb24gbG9zIGHDsW9zIGEgcGFydGlyIGRlIDE5OTcuDQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKHllYXIgPj0gMTk5NykNCmBgYA0KDQpQZXJvIHNpIHF1aXNpw6lyYW1vcyBxdWVkYXJub3MgY29uIGxvcyBhw7FvcyAxOTUyLCAxOTcyLCAyMDAyLCAyMDA3LCDCv2PDs21vIGxvIHBvZHLDrWFtb3MgaGFjZXI/DQoNCkxvIHBvZHLDrWFtb3MgbG9ncmFyIGNvbiBsYSBmdW5jacOzbiBgJWluJWA6DQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTIsIDE5NzIsIDIwMDIsIDIwMDcpLA0KICAgICAgICAgY291bnRyeSA9PSAiTWV4aWNvIikNCmBgYA0KDQoNCkFob3JhLCBzaSBkZXNlw6FyYW1vcyBvYnRlbmVyIHVuYSBzdWJncsOhZmljYSBkZSBsw61uZWFzIGRlIGN1YW50cm8gcGHDrXNlcyBhc2nDoXRpY29zIChOZXBhbCwgSXJhaywgQ2FtYm9kaWEgeSBDaGluYSksIGxvIHBvZHLDrWFtb3MgaGFjZXIgZGUgbGEgc2lndWllbnRlIGZvcm1hOg0KDQpgYGB7ciBnYXAgcGxvdCBmYWNldHMgY291bnRyeX0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiTmVwYWwiLCAiSXJhcSIsICJDYW1ib2RpYSIsIkNoaW5hIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKSArDQogIGdlb21fbGluZSgpICsgDQogIGZhY2V0X3dyYXAofiBjb3VudHJ5KSArDQogIGdndGl0bGUoIlNlcGFyYWNpw7NuIGRlIGxvcyBwYcOtc2VzIHBvciBmYWNldGFzIikNCmBgYA0KDQpPdHJhIGFsdGVybmF0aXZhIHNlcsOtYSBtb3N0cmFyIHVuYSBzb2xhIGdyw6FmaWNhIHkgZGVmaW5pciBlbCBjb2xvciBkZSBsw61uZWEgcG9yIHBhw61zLiBBcXXDrSBzZSBlamVtcGxpZmljYSB0YW1iacOpbiBjw7NtbyBjYW1iaWFyIGVsIG5vbWJyZSBkZSBsb3MgZWplcywgbGEgcG9zaWNpw7NuIGRlIGxhIGxleWVuZGEsIGVudHJlIG90cm9zLg0KDQpgYGB7ciBnYXAgcGxvdCBjb3VudHJ5IGNvbG9yfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJJbmRvbmVzaWEiLCJJbmRpYSIsIk9tYW4iLCAiVGFpd2FuIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsIGNvbG9yID0gY291bnRyeSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICB5bGFiKCJFc3BlcmFuemEgZGUgdmlkYSAoYcOxb3MpIikgKyB4bGFiKCIiKSArDQogIGdndGl0bGUoIkNhbWJpbyBkZSBsYSBlc3BlcmFuemEgZGUgdmlkYSBwYXJhIGFsZ3Vub3MgcGFpc2VzIGFzacOhdGljb3MiKSArDQogIGxhYnMoY29sb3IgPSAiUGHDrXMiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQpPdHJhIG1hbmVyYSBkZSBlc3BlY2lmaWNhciBsb3Mgbm9tYnJlcyBkZSBlamVzIHkgZWwgdMOtdHVsbyBlcyBkaXJlY3RhbWVudGUgZGVudHJvIGRlIGBsYWJzKClgOg0KDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiSW5kb25lc2lhIiwiSW5kaWEiLCJPbWFuIiwgIlRhaXdhbiIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvdW50cnkpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh4ID0gIiIsIA0KICAgICAgIHkgPSAiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIsIA0KICAgICAgIHRpdGxlID0gIkNhbWJpbyBkZSBsYSBlc3BlcmFuemEgZGUgdmlkYSBlbiBhbGd1bm9zIHBhw61zZXMgYXNpw6F0aWNvcyIsIA0KICAgICAgIGNvbG9yID0gIiIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNClNlIHBvZHLDrWFuIGhhY2VyIG3DoXMgY29uZmlndXJhY2lvbmVzOg0KDQpgYGB7ciBnYXAgcGxvdCBjb3VudHJ5IGNvbG9yIGxpbmV0eXBlfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJJbmRvbmVzaWEiLCJJbmRpYSIsIk9tYW4iLCAiVGFpd2FuIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsIGNvbG9yID0gY291bnRyeSwgbGluZXR5cGUgPSBjb3VudHJ5KSkgKw0KICBnZW9tX2xpbmUoKSArDQogIHlsYWIoIkVzcGVyYW56YSBkZSB2aWRhIChhw7FvcykiKSArIHhsYWIoIiIpICsNCiAgZ2d0aXRsZSgiQ2FtYmlvIGRlIGxhIGVzcGVyYW56YSBkZSB2aWRhIHBhcmEgYWxndW5vcyBwYWlzZXMgYXNpw6F0aWNvcyIpICsNCiAgbGFicyhjb2xvciA9ICIiLCBsaW5ldHlwZSA9IiIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQoNClBvZGVtb3MgYW5hbGl6YXIgbGEgcmVsYWNpw7NuIGVudHJlIGxhIGVzcGVyYW56YSBkZSB2aWRhIHkgZWwgUElCIHBlciBjw6FwaXRhLCB5YSBxdWUgc2UgZGljZSBxdWUgZXhpc3RlIHVuYSByZWxhY2nDs24gZGlyZWN0YSBlbnRyZSBhbWJhcy4NCg0KSGFyZW1vcyBlbCBhbsOhbGlzaXMgcGFyYSBlbCBhw7FvIDIwMDc6DQoNCg0KYGBge3IgZ2FwIGxpZmVFeHAgR0RQIDIwMDd9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQsDQogICAgICAgICAgICAgc2l6ZSA9IHBvcCkpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIHNjYWxlX3hfbG9nMTAoKSArDQogIHlsYWIoIkVzcGVyYW56YSBkZSB2aWRhIChhw7FvcykiKSArDQogIHhsYWIoIlBJQiBwZXIgY8OhcGl0YSAoVVNEIGNvbiBhanVzdGUgaW5mbGFjaW9uYXJpbywgZXNjYWxhIGxvZzEwKSIpICsgDQogIGxhYnMoY29sb3IgPSIiLCBzaXplPSIiKQ0KYGBgDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQ2FuYWRhIiwgIk1leGljbyIsICJCcmF6aWwiKSwNCiAgICAgICAgIHllYXIgPT0gMjAwNykgJT4lIA0KICBzZWxlY3QoeWVhciwgY291bnRyeSwgcG9wKQ0KYGBgDQoNCg0KUGVybywgwr9xdcOpIHBhc2Egc2kgcXVlcmVtb3Mgb2JzZXJ2YXIgZWwgY2FtYmlvIGRlIGVzdG9zIGZhY3RvcmVzIGEgbG8gbGFyZ28gZGVsIHRpZW1wbz8gQ2xhcm8sIHBvZHLDrWFtb3MgY3JlYXIgbXVjaGFzIGdyw6FmaWNhcyBkaXN0aW50YXMsIGNhbWJpYW5kbyBlbCBhcmd1bWVudG8gYGZpbHRlcih5ZWFyID09ICJjYWRhIHVubyBkZSBsb3MgYcOxb3MiKWAuIFBlcm8gZXN0bywgYXBhcnRlIGRlIHF1ZSBzZXLDrWEgbGFib3Jpb3NvLCBubyBzZXLDrWEgcHLDoWN0aWNvIHBhcmEgYW5hbGl6YXJsby4NCg0KIyBHcsOhZmljYXMgaW50ZXJhY3RpdmFzIHsudGFic2V0fQ0KDQojIyBgcGxvdGx5YA0KDQpMbyBxdWUgcG9kZW1vcyBoYWNlciBlcyBjcmVhciB1bmEgZ3LDoWZpY2EgaW50ZXJhY3RpdmEsIGFwb3lhZG9zIGRlIGxhIHBhcXVldGVyw61hIFtgcGxvdGx5YF0oaHR0cHM6Ly9wbG90bHkuY29tL3IvKS4gTG9zIGNhbWJpb3MgcXVlIHRlbmVtb3MgcXVlIGhhY2VyIGVuIGVzdGUgY2FzbyBlbiBwYXJ0aWN1bGFyIHNvbiBtdXkgc2VuY2lsbG9zLiBQdWVkZW4gY29uc3VsdGFyIFtlc3RlIGxpYnJvIGVsZWN0csOzbmljb10oaHR0cHM6Ly9wbG90bHktci5jb20vaW5kZXguaHRtbCkgcGFyYSBtw6FzIGRldGFsbGVzLg0KDQoqIEhhYmVyIGluc3RhbGFkbyB5IGNhcmdhZG8gYHBsb3RseWANCiogQWdyZWdhciBgYWVzKGZyYW1lID0geWVhcilgIGEgbGEgZXN0w6l0aWNhIGRlIGxhIGdyw6FmaWNhLg0KKiBHdWFyZGFyIGVsIGdyw6FmaWNvIGVuIHVuYSB2YXJpYWJsZSAoZWwgbm9tYnJlIGVzIGluZGlmZXJlbnRlKSwgeSBwb3N0ZXJpb3JtZW50ZSBlamVjdXRhciBsYSBmdW5jacOzbiBgZ2dwbG90bHkoKWAgY29uIGxhIHZhcmlhYmxlIHF1ZSBjb250aWVuZSBhbCBncsOhZmljby4NCg0KKipOT1RBOioqIENhc2kgY3VhbHF1aWVyIGdyw6FmaWNvIGhlY2hvIGNvbiBgZ2dwbG90MmAgc2UgcHVlZGUgY29udmVydGlyIGVuIHVubyBpbnRlcmFjdGl2byBjb24gbGEgZnVuY2nDs24gYGdncGxvdGx5KClgLg0KDQoNCmBgYHtyIHBsb3RseSBnYXAsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9DQppbnRfcGxvdDEgPC0gZ2FwbWluZGVyICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQsDQogICAgICAgICAgICAgc2l6ZSA9IHBvcCwgbGFiZWwgPSBjb3VudHJ5KSkgKw0KICBnZW9tX3BvaW50KGFlcyhmcmFtZSA9IHllYXIpKSArIA0KICBzY2FsZV94X2xvZzEwKCkgKyANCiAgeWxhYigiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIpICsNCiAgeGxhYigiUElCIHBlciBjw6FwaXRhIChVU0QgY29uIGFqdXN0ZSBpbmZsYWNpb25hcmlvKSIpICsgDQogIGxhYnMoY29sb3IgPSIiLCBzaXplPSIiKQ0KDQpnZ3Bsb3RseShpbnRfcGxvdDEpDQpgYGANCg0KYGBge3IgcGxvdGx5IGJ5IGZhY2V0cywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0NCmludF9wbG90MiA8LSBnYXBtaW5kZXIgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvdW50cnksDQogICAgICAgICAgICAgc2l6ZSA9IHBvcCwgbGFiZWwgPSBjb3VudHJ5KSkgKw0KICBnZW9tX3BvaW50KGFlcyhmcmFtZSA9IHllYXIpKSArIA0KICBzY2FsZV94X2xvZzEwKCkgKyANCiAgZmFjZXRfd3JhcCh+IGNvbnRpbmVudCkgKw0KICB5bGFiKCJFc3BlcmFuemEgZGUgdmlkYSAoYcOxb3MpIikgKw0KICB4bGFiKCJQSUIgcGVyIGPDoXBpdGEgKFVTRCBjb24gYWp1c3RlIGluZmxhY2lvbmFyaW8pIikgKyANCiAgIyBsYWJzKGNvbG9yID0iIiwgc2l6ZT0iIikNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQogIA0KZ2dwbG90bHkoaW50X3Bsb3QyKQ0KYGBgDQoNCk90cm8gdGlwbyBkZSBncsOhZmljbyBxdWUgcHVlZGUgcHJvcG9yY2lvbmFybm9zIG11Y2hhIGluZm9ybWFjacOzbiBlcyB1biAqZGlhZ3JhbWEgZGUgY2FqYSB5IGJpZ290ZXMqLiBBcXXDrSwgbGEgaW50ZXJwcmV0YWNpw7NuIGVzIGFsZ28gYXPDrToNCg0KKiBMb3MgYmlnb3RlcyBtdWVzdHJhbiBsb3MgdmFsb3JlcyBtw61uaW1vIHkgbcOheGltbyAoc2luIGNvbnNpZGVyYXIgKm91dGxpZXJzKiksDQoqIGVsIGluaWNpbyBkZSBsYSBjYWphIHJlcHJlc2VudGEgZWwgcHJpbWVyIGN1YXJ0aWwgKDI1JSBkZSBsb3MgZGF0b3MpLA0KKiBMYSBsw61uZWEgaW50ZXJuYSBkZSBsYSBjYWphIGVzIGxhIG1lZGlhbmEgKGVsIDUwJSBkZSBsb3MgZGF0b3MpLA0KKiBlbCBmaW5hbCBkZSBsYSBjYWphIG11ZXN0cmEgZWwgdGVyY2VyIGN1YXJ0aWwgKDc1JSBkZSBsb3MgZGF0b3MpIHksDQoqIGVuIGNhc28gZGUgcXVlIGxhIGdyw6FmaWNhIG11ZXN0cmUgcHVudG9zIGZ1ZXJhIGRlIGxhIGNhamEsIHNlIGNvbnNpZGVyYXLDrWFuIGNvbW8gKm91dGxpZXJzKi4NCg0KYGBge3IgZ2FwIGJveHBsb3R9DQpnYXBfYm94IDwtIGdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKHllYXIgPT0gMjAwNykgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBjb250aW5lbnQsIHkgPSBsaWZlRXhwKSkgKw0KICBnZW9tX2JveHBsb3QoKQ0KDQpnZ3Bsb3RseShnYXBfYm94KQ0KYGBgDQoNCkRlZmluaWVuZG8gdW5hIGZ1bmNpw7NuIGVzcGVjaWFsLCBzZSBwdWVkZW4gY3JlYXIgZ3LDoWZpY2FzIGFjdW11bGF0aXZhcyBkZSBsw61uZWFzIHRhbWJpw6luOg0KDQpgYGB7ciBwbG90bHkgY3VtdWxhdGl2ZSBsaW5lfQ0KaW52aXNpYmxlKGdldFN5bWJvbHMoIkFBUEwiLHNyYz0neWFob28nKSkNCg0KZGYgPC0gZGF0YS5mcmFtZShEYXRlPXpvbzo6aW5kZXgoQUFQTCksY29yZWRhdGEoQUFQTCkpDQpkZiA8LSB0YWlsKGRmLCAzMCkNCmRmJElEIDwtIHNlcS5pbnQobnJvdyhkZikpDQoNCmFjY3VtdWxhdGVfYnkgPC0gZnVuY3Rpb24oZGF0LCB2YXIpIHsNCiAgdmFyIDwtIGxhenlldmFsOjpmX2V2YWwodmFyLCBkYXQpDQogIGx2bHMgPC0gcGxvdGx5Ojo6Z2V0TGV2ZWxzKHZhcikNCiAgZGF0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKGx2bHMpLCBmdW5jdGlvbih4KSB7DQogICAgY2JpbmQoZGF0W3ZhciAlaW4lIGx2bHNbc2VxKDEsIHgpXSwgXSwgZnJhbWUgPSBsdmxzW1t4XV0pDQogIH0pDQogIGRwbHlyOjpiaW5kX3Jvd3MoZGF0cykNCn0NCg0KZGYgPC0gZGYgJT4lDQogIGFjY3VtdWxhdGVfYnkofklEKQ0KDQpwIDwtIGdncGxvdChkZixhZXMoSUQsIEFBUEwuQ2xvc2UsIGZyYW1lID0gZnJhbWUpKSArDQogIGdlb21fbGluZSgpDQoNCmZpZyA8LSBnZ3Bsb3RseShwKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkFBUEw6IExhc3QgMzAgZGF5cyIsDQogICAgeWF4aXMgPSBsaXN0KA0KICAgICAgdGl0bGUgPSAiQ2xvc2UiLA0KICAgICAgemVyb2xpbmUgPSBGLA0KICAgICAgdGlja3ByZWZpeCA9ICIkIg0KICAgICksDQogICAgeGF4aXMgPSBsaXN0KA0KICAgICAgdGl0bGUgPSAiRGF5IiwNCiAgICAgIHplcm9saW5lID0gRiwgDQogICAgICBzaG93Z3JpZCA9IEYNCiAgICApDQogICkgJT4lIA0KICBhbmltYXRpb25fb3B0cygNCiAgICBmcmFtZSA9IDEwMCwgDQogICAgdHJhbnNpdGlvbiA9IDAsIA0KICAgIHJlZHJhdyA9IEZBTFNFDQogICkgJT4lDQogIGFuaW1hdGlvbl9zbGlkZXIoDQogICAgY3VycmVudHZhbHVlID0gbGlzdCgNCiAgICAgIHByZWZpeCA9ICJEYXkgIg0KICAgICkNCiAgKQ0KDQpmaWcNCmBgYA0KDQoNCg0KIyMgYGdnYW5pbWF0ZWANCg0KRXN0byBubyBmdW5jaW9uYSBpZ3VhbCBwYXJhIHVuIGdyw6FmaWNvIGRlIGzDrW5lYXMuIEV4aXN0ZSBvdHJhIHBhcXVldGVyw61hIHF1ZSBub3MgcGVybWl0ZSBoYWNlciBjb3NhcyBzaW1pbGFyZXM6IFtgZ2dhbmltYXRlYF0oaHR0cHM6Ly9nZ2FuaW1hdGUuY29tL2FydGljbGVzL2dnYW5pbWF0ZS5odG1sKS4gW0VzdGEgcMOhZ2luYV0oaHR0cHM6Ly93d3cuZGF0YW5vdmlhLmNvbS9lbi9ibG9nL2dnYW5pbWF0ZS1ob3ctdG8tY3JlYXRlLXBsb3RzLXdpdGgtYmVhdXRpZnVsLWFuaW1hdGlvbi1pbi1yLykgY29udGllbmUgdW4gYnJldmUgdHV0b3JpYWwgZGUgdmFyaWFzIG9wY2lvbmVzLg0KDQoqKk5PVEE6KiogKlNlIHJlcXVpZXJlIGluc3RhbGFyIGxhcyBwYXF1ZXRlcsOtYXMgYHBuZ2AgeSBgZ2lmc2tpYCBhZGljaW9uYWxlcyBhIGBnZ2FuaW1hdGVgLg0KDQpgYGB7ciBnZ2FuaW1hdGUsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBldmFsPUZBTFNFfQ0KcDEgPC0gZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJNZXhpY28iLCAiVW5pdGVkIFN0YXRlcyIsICJDaGlsZSIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsDQogICAgICAgICAgICAgY29sb3IgPSBjb3VudHJ5KSkgKyANCiAgZ2VvbV9saW5lKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKw0KICBsYWJzKHggPSAiQcOxbyIsIHkgPSAiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIsIA0KICAgICAgIHRpdGxlID0gIkV2b2x1Y2nDs24gZGUgbGEgZXNwZXJhbnphIGRlIHZpZGEgZW4gZWwgdGllbXBvIikNCg0KcDEgKyB0cmFuc2l0aW9uX3JldmVhbCh5ZWFyKQ0KDQphbmltX3NhdmUoZmlsZW5hbWUgPSAiZmlncy9MaWZlRXhwX2dnYW5pbS5naWYiKQ0KYGBgDQoNCihmaWdzL0xpZmVFeHBfZ2dhbmltLmdpZikNCg0KDQoNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZScsIGV2YWw9RkFMU0V9DQpwIDwtIGdncGxvdCgNCiAgYWlycXVhbGl0eSwNCiAgYWVzKERheSwgVGVtcCwgZ3JvdXAgPSBNb250aCwgY29sb3IgPSBmYWN0b3IoTW9udGgpKQ0KICApICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArDQogIGxhYnMoeCA9ICJEYXkgb2YgTW9udGgiLCB5ID0gIlRlbXBlcmF0dXJlIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNCg0KcCArIHRyYW5zaXRpb25fcmV2ZWFsKERheSkNCg0KYW5pbV9zYXZlKGZpbGVuYW1lID0gImZpZ3MvYWlycXVhbGl0eS5naWYiKQ0KYGBgDQooZmlncy9haXJxdWFsaXR5LmdpZikNCg0KDQoNCg0K